From ecc62f335f23ba1ba3f74529fdb938d6ec89400e Mon Sep 17 00:00:00 2001 From: William Richard Date: Thu, 28 Apr 2016 12:49:37 -0400 Subject: [PATCH] Fix up a few things related to min, start and gateway address (#445) * Fix up a few things related to min, start and gateway address - the get address pools api was incorrectly only returning the min address, not the configured gateway - the IP allocation code was always starting at min address, instead of starting at start address - min address should be the min address in the range, not the configured start address. - Added a basic unit test for the ipam api --- .../actions/ipaddress/GetPoolsAction.scala | 2 +- app/collins/models/shared/IpAddressable.scala | 4 +- app/collins/util/IpAddress.scala | 2 +- test/collins/controllers/IpamApiSpec.scala | 45 +++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 test/collins/controllers/IpamApiSpec.scala diff --git a/app/collins/controllers/actions/ipaddress/GetPoolsAction.scala b/app/collins/controllers/actions/ipaddress/GetPoolsAction.scala index 5c8a6491e..fbd85ab19 100644 --- a/app/collins/controllers/actions/ipaddress/GetPoolsAction.scala +++ b/app/collins/controllers/actions/ipaddress/GetPoolsAction.scala @@ -57,7 +57,7 @@ case class GetPoolsAction( "NETWORK" -> JsString(formatNetworkAddress(pool.network)), "START_ADDRESS" -> JsString(pool.startAddress.getOrElse("Unspecified")), "SPECIFIED_GATEWAY" -> JsString(pool.gateway.getOrElse("Unspecified")), - "GATEWAY" -> JsString(pool.ipCalc.minAddress), + "GATEWAY" -> JsString(pool.gateway.getOrElse(pool.ipCalc.minAddress)), "BROADCAST" -> JsString(pool.ipCalc.broadcastAddress), "POSSIBLE_ADDRESSES" -> JsNumber(pool.ipCalc.addressCount) ) diff --git a/app/collins/models/shared/IpAddressable.scala b/app/collins/models/shared/IpAddressable.scala index f39438d59..99d2d82b7 100644 --- a/app/collins/models/shared/IpAddressable.scala +++ b/app/collins/models/shared/IpAddressable.scala @@ -127,11 +127,11 @@ trait IpAddressStorage[T <: IpAddressable] extends Schema with AnormAdapter[T] w * For a range 0L..20L, used addresses List(17,18,19,20), the result will be None (allocate from beginning) */ protected def getCurrentLowestLocalMaxAddress(calc: IpAddressCalc)(implicit scope: Option[String]): Option[Long] = inTransaction { - val minAddress = calc.minAddressAsLong + val startAddress = calc.startAddressAsLong val maxAddress = calc.maxAddressAsLong val sortedAddresses = from(tableDef)(t => where( - (t.address gte minAddress) and + (t.address gte startAddress) and (t.address lte maxAddress)) select (t.address) orderBy (t.address asc)).toSeq diff --git a/app/collins/util/IpAddress.scala b/app/collins/util/IpAddress.scala index b9b34b341..dbe3bc3b9 100644 --- a/app/collins/util/IpAddress.scala +++ b/app/collins/util/IpAddress.scala @@ -99,7 +99,7 @@ case class IpAddressCalc(network: String, startAt: Option[String] = None) { def lastOctetInRange: Long = IpAddress.lastOctet(maxAddressAsLong) def startAddress: String = startAt.getOrElse(minAddress) def startAddressAsLong = IpAddress.toLong(startAddress) - def minAddress: String = startAt.getOrElse(subnetInfo.getLowAddress()) + def minAddress: String = subnetInfo.getLowAddress() def minAddressAsLong = IpAddress.toLong(minAddress) def maxAddress: String = subnetInfo.getHighAddress() def maxAddressAsLong = IpAddress.toLong(maxAddress) diff --git a/test/collins/controllers/IpamApiSpec.scala b/test/collins/controllers/IpamApiSpec.scala new file mode 100644 index 000000000..71f6688c3 --- /dev/null +++ b/test/collins/controllers/IpamApiSpec.scala @@ -0,0 +1,45 @@ +package collins.controllers + +import collins._ +import org.specs2._ +import specification._ +import play.api.test.WithApplication +import org.specs2.matcher.JsonMatchers + +class IpamApiSpec extends mutable.Specification with ControllerSpec { + + "IPAM API Specification".title + + args(sequential = true) + + "the REST API" should { + "Support getting pools" in new WithApplication with AssetApiHelper { + override val assetTag = "tumblrtag42" + val getRequest = FakeRequest("GET", "/api/address/pools") + val getResult = Extract.from(api.getAddressPools("true").apply(getRequest)) + getResult must haveStatus(200) + getResult must haveJsonData.which { s => + s must /("data") */("POOLS") */ ("NAME" -> "ADMIN-OPS") + s must /("data") */("POOLS") */ ("GATEWAY" -> "172.16.56.1") + s must /("data") */("POOLS") */ ("START_ADDRESS" -> "172.16.56.5") + s must /("data") */("POOLS") */ ("BROADCAST" -> "172.16.56.255") + s must /("data") */("POOLS") */ ("POSSIBLE_ADDRESSES" -> 254) + } + } + "Support creating an address starting with start address" in new WithApplication with AssetApiHelper { + override val assetTag = "tumblrtag42" + val pool = "ADMIN-OPS" + createAsset() must haveStatus(201) + val createRequest = FakeRequest("PUT", "/api/asset/%s/address?pool=%s".format(assetTag, pool)) + val createResult = Extract.from(api.allocateAddress(assetTag).apply(createRequest)) + createResult must haveStatus(201) + createResult must haveJsonData.which { s => + s must /("data") */("ADDRESSES") */ ("ASSET_TAG" -> assetTag) + s must /("data") */("ADDRESSES") */ ("ADDRESS" -> "172.16.56.5") + s must /("data") */("ADDRESSES") */ ("GATEWAY" -> "172.16.56.1") + s must /("data") */("ADDRESSES") */ ("NETMASK" -> "255.255.255.0") + s must /("data") */("ADDRESSES") */ ("POOL" -> pool) + } + } + } +}