Parse policies and correct cron string definition
authorGeorgios Gousios <gousiosg@gmail.com>
Mon, 31 Oct 2011 13:19:28 +0000 (15:19 +0200)
committerGeorgios Gousios <gousiosg@gmail.com>
Mon, 31 Oct 2011 13:19:28 +0000 (15:19 +0200)
logic/src/main/scala/gr/grnet/aquarium/logic/accounting/dsl/DSL.scala
logic/src/test/resources/policy.yaml
logic/src/test/scala/gr/grnet/aquarium/logic/test/DSLTest.scala

index 0771d4e..8443efb 100644 (file)
@@ -19,6 +19,8 @@ object DSL extends Loggable {
     val resources = "resources"
     val policies = "policies"
     val policy = "policy"
+    val pricelists = "pricelists"
+    val pricelist = "pricelist"
     val name = "name"
     val overrides = "overrides"
     val effective = "effective"
@@ -32,6 +34,9 @@ object DSL extends Loggable {
   private val emptyPolicy = DSLPolicy("", None, Map(),
     DSLTimeFrame(new Date(0), None, Option(List())))
 
+  private val emptyPriceList = DSLPriceList("", None, Map(),
+    DSLTimeFrame(new Date(0), None, Option(List())))
+
   def parse(input: InputStream) : DSLCreditPolicy = {
     logger.debug("Policy parsing started")
 
@@ -47,6 +52,13 @@ object DSL extends Loggable {
 
     logger.debug("Policies: %s".format(policies))
 
+    val pricelists = parsePriceLists(
+      policy./(Vocabulary.pricelists).asInstanceOf[YAMLListNode],
+      resources, List()
+    )
+
+    logger.debug("Pricelists: %s".format(pricelists))
+
     DSLCreditPolicy(policies, List(), resources, List())
   }
 
@@ -135,6 +147,75 @@ object DSL extends Loggable {
     DSLPolicy(name, overr, algos, timeframe)
   }
 
+  def parsePriceLists(pricelists: YAMLListNode,
+                    resources: List[DSLResource],
+                    results: List[DSLPriceList]): List[DSLPriceList] = {
+    pricelists.head match {
+      case YAMLEmptyNode => return List()
+      case _ =>
+    }
+
+    val superName = pricelists.head / Vocabulary.overrides
+    val tmpl = superName match {
+      case y: YAMLStringNode =>
+        results.find(p => p.name.equals(y.string)) match {
+          case Some(x) => x
+          case None => throw new DSLParseException(
+            "Cannot find super pricelist %s".format(superName))
+        }
+      case YAMLEmptyNode => emptyPriceList
+      case _ => throw new DSLParseException(
+        "Super pricelist name %s not a string".format())
+    }
+
+    val pl = constructPriceList(pricelists.head.asInstanceOf[YAMLMapNode],
+      tmpl, resources)
+
+    val tmpresults = results ++ List(pl)
+    List(pl) ++ parsePriceLists(pricelists.tail, resources, tmpresults)
+  }
+
+  def constructPriceList(pl: YAMLMapNode, tmpl: DSLPriceList,
+                         resources: List[DSLResource]): DSLPriceList = {
+    val name = pl / Vocabulary.name match {
+      case x: YAMLStringNode => x.string
+      case YAMLEmptyNode => throw new DSLParseException("Policy does not have a name")
+    }
+
+    val overr = pl / Vocabulary.overrides match {
+      case x: YAMLStringNode => Some(x.string)
+      case YAMLEmptyNode => None
+    }
+
+    val prices = resources.map {
+      r =>
+        val algo = pl / r.name match {
+          case x: YAMLStringNode => x.string
+          case y: YAMLIntNode => y.int.toString
+          case z: YAMLDoubleNode => z.double.toString
+          case YAMLEmptyNode => tmpl.equals(emptyPolicy) match {
+            case false => tmpl.prices.getOrElse(r,
+              throw new DSLParseException(("Severe! Superpolicy does not " +
+                "specify an algorithm for resource:%s").format(r.name)))
+            case true => throw new DSLParseException(("Cannot find " +
+              "calculation algorithm for resource %s in either policy %s or a" +
+              " superpolicy").format(r.name, name))
+          }
+        }
+        Map(r -> algo)
+    }.foldLeft(Map[DSLResource, Any]())((x, y) => x ++ y)
+
+    val timeframe = pl / Vocabulary.effective match {
+      case x: YAMLMapNode => parseTimeFrame(x)
+      case YAMLEmptyNode => tmpl.equals(emptyPolicy) match {
+        case false => tmpl.effective
+        case true => throw new DSLParseException(("Cannot find effectivity " +
+          "period for policy %s ").format(name))
+      }
+    }
+    DSLPriceList(name, overr, Map(), timeframe)
+  }
+
   /** Parse a timeframe declaration */
   def parseTimeFrame(timeframe: YAMLMapNode): DSLTimeFrame = {
     val from = timeframe / Vocabulary.from match {
@@ -222,7 +303,7 @@ object DSL extends Loggable {
     ).flatten.toList
   }
 
-  /** Merge two policies, field by field */
+  /** Merge two pricelists, field by field */
   def mergePolicy(policy: DSLPolicy, onto: DSLPolicy): DSLPolicy = {
     DSLPolicy(onto.name, onto.overrides,
       mergeMaps(policy.algorithms, onto.algorithms),
index ad3787a..22984fa 100644 (file)
@@ -46,8 +46,8 @@ creditpolicy:
       diskspace: 0.05
       effective:
         repeat:
-          - start: "00 00 2 Tue *"
-            end:   "00 00 2 Wed *"
+          - start: "00 02 * * Tue"
+            end:   "00 02 * * Wed"
         from: 0
     - pricelist:
       name: foobar
@@ -57,10 +57,10 @@ creditpolicy:
       diskspace: 0.05
       effective:
         repeat:
-          - start: "00 00 12 * *"
-            end:   "00 00 14 * *"
-          - start: "00 00 18 * *"
-            end:   "00 00 20 * *"
+          - start: "00 12 * * *"
+            end:   "00 14 * * *"
+          - start: "00 18 * * *"
+            end:   "00 20 * * *"
         from: 0
 
   agreements:
index ee6f7b2..99d8ce9 100644 (file)
@@ -99,6 +99,10 @@ class DSLTest {
     assertEquals(output.size, 4)
     assertEquals(output(2), DSLCronSpec(12, 4, 3, 3, -1))
 
+    input = "12 4 3 jaN-ApR MOn-FRi"
+    output = DSL.parseCronString(input)
+    assertEquals(output.size, 20)
+
     input = "12 4 foo jaN-ApR *"
     assertThrows(DSL.parseCronString(input))