2
0
mirror of https://github.com/VinylDNS/vinyldns synced 2025-08-31 14:25:30 +00:00

max zone size (#584)

* max zone size rule

* refactor IOs
This commit is contained in:
Nima Eskandary
2019-04-26 09:47:29 -04:00
committed by Rebecca Star
parent 32156cb5bb
commit c1d88c5dca
6 changed files with 47 additions and 17 deletions

View File

@@ -44,5 +44,13 @@ class ZoneViewLoaderIntegrationSpec extends WordSpec with Matchers {
.load() .load()
.unsafeRunSync()) .unsafeRunSync())
} }
"return a failure if the zone is larger than the max zone size" in {
assertThrows[ZoneTooLargeError](
DnsZoneViewLoader(Zone("vinyldns.", "test@test.com"), DnsZoneViewLoader.dnsZoneTransfer, 1)
.load()
.unsafeRunSync()
)
}
} }
} }

View File

@@ -8,6 +8,8 @@ vinyldns {
# if we should start up polling for change requests, set this to false for the inactive cluster # if we should start up polling for change requests, set this to false for the inactive cluster
processing-disabled = false processing-disabled = false
max-zone-size = 60000 # number of records that can be in a zone
queue { queue {
class-name = "vinyldns.sqs.queue.SqsMessageQueueProvider" class-name = "vinyldns.sqs.queue.SqsMessageQueueProvider"

View File

@@ -112,4 +112,6 @@ object VinylDNSConfig {
if (vinyldnsConfig.hasPath(key)) { if (vinyldnsConfig.hasPath(key)) {
vinyldnsConfig.getStringList(key).asScala.toList vinyldnsConfig.getStringList(key).asScala.toList
} else List() } else List()
lazy val maxZoneSize: Int = vinyldnsConfig.as[Option[Int]]("max-zone-size").getOrElse(60000)
} }

View File

@@ -240,3 +240,14 @@ case class ConnectionFailed(zone: Zone, message: String) extends Throwable(messa
case class ZoneValidationFailed(zone: Zone, errors: List[String], message: String) case class ZoneValidationFailed(zone: Zone, errors: List[String], message: String)
extends Throwable(message) extends Throwable(message)
case class ZoneTooLargeError(msg: String) extends Throwable(msg)
object ZoneTooLargeError {
def apply(zone: Zone, zoneSize: Int, maxZoneSize: Int): ZoneTooLargeError = new ZoneTooLargeError(
s"""
|ZoneTooLargeError: Zone '${zone.name}' (id: '${zone.id}') contains $zoneSize records
|which exceeds the max of $maxZoneSize
""".stripMargin.replace("\n", " ")
)
}

View File

@@ -27,12 +27,14 @@ import vinyldns.core.domain.zone.Zone
import vinyldns.core.route.Monitored import vinyldns.core.route.Monitored
import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
import vinyldns.core.domain.record.{RecordSetRepository, RecordType}
trait ZoneViewLoader { trait ZoneViewLoader {
def load: () => IO[ZoneView] def load: () => IO[ZoneView]
} }
object DnsZoneViewLoader extends DnsConversions { object DnsZoneViewLoader extends DnsConversions {
def dnsZoneTransfer(zone: Zone): ZoneTransferIn = { def dnsZoneTransfer(zone: Zone): ZoneTransferIn = {
val conn = val conn =
ZoneConnectionValidator ZoneConnectionValidator
@@ -54,7 +56,10 @@ object DnsZoneViewLoader extends DnsConversions {
DnsZoneViewLoader(zone, dnsZoneTransfer) DnsZoneViewLoader(zone, dnsZoneTransfer)
} }
case class DnsZoneViewLoader(zone: Zone, zoneTransfer: Zone => ZoneTransferIn) case class DnsZoneViewLoader(
zone: Zone,
zoneTransfer: Zone => ZoneTransferIn,
maxZoneSize: Int = VinylDNSConfig.maxZoneSize)
extends ZoneViewLoader extends ZoneViewLoader
with DnsConversions with DnsConversions
with Monitored { with Monitored {
@@ -62,23 +67,20 @@ case class DnsZoneViewLoader(zone: Zone, zoneTransfer: Zone => ZoneTransferIn)
def load: () => IO[ZoneView] = def load: () => IO[ZoneView] =
() => () =>
monitor("dns.loadZoneView") { monitor("dns.loadZoneView") {
IO { for {
zoneXfr <- IO {
val xfr = zoneTransfer(zone) val xfr = zoneTransfer(zone)
xfr.run() xfr.run()
val rawDnsRecords: List[DNS.Record] =
xfr.getAXFR.asScala.map(_.asInstanceOf[DNS.Record]).toList.distinct xfr.getAXFR.asScala.map(_.asInstanceOf[DNS.Record]).toList.distinct
// not accepting unknown record types
val supportedRecords =
rawDnsRecords.filter(record => fromDnsRecordType(record.getType) != RecordType.UNKNOWN)
val dnsZoneName = zoneDnsName(zone.name)
val recordSets = supportedRecords.map(toRecordSet(_, dnsZoneName, zone.id))
ZoneView(zone, recordSets)
} }
rawDnsRecords = zoneXfr.filter(record =>
fromDnsRecordType(record.getType) != RecordType.UNKNOWN)
_ <- if (rawDnsRecords.length > maxZoneSize)
IO.raiseError(ZoneTooLargeError(zone, rawDnsRecords.length, maxZoneSize))
else IO.pure(Unit)
dnsZoneName <- IO(zoneDnsName(zone.name))
recordSets <- IO(rawDnsRecords.map(toRecordSet(_, dnsZoneName, zone.id)))
} yield ZoneView(zone, recordSets)
} }
} }

View File

@@ -464,6 +464,11 @@ vinyldns {
port = 9000 port = 9000
} }
# The maximum number of records VinylDNS will load when syncing a DNS Zone
# this is to prevent possible out of memory errors when loading a Zone
# this does not stop the zone from existing in DNS, but you will not be able to manage it in VinylDNS if the number of records exceeds the max
max-zone-size = 60000
# the delay between zone syncs so we are not syncing too often # the delay between zone syncs so we are not syncing too often
sync-delay = 10000 sync-delay = 10000