package gr.grnet.aquarium.logic.accounting
+import dsl.{Timeslot, DSLPolicy, DSL}
import gr.grnet.aquarium.Configurator._
-import dsl.DSL
-import com.ckkloverdos.maybe.{NoVal, Failed, Just}
-import gr.grnet.aquarium.util.Loggable
import java.io.{InputStream, FileInputStream, File}
+import java.util.Date
+import com.ckkloverdos.maybe.{Maybe, Just}
+import gr.grnet.aquarium.util.date.TimeHelpers
+import gr.grnet.aquarium.logic.events.PolicyEntry
+import gr.grnet.aquarium.util.{CryptoUtils, Loggable}
/**
* Searches for and loads the applicable accounting policy
* @author Georgios Gousios <gousiosg@gmail.com>
*/
object Policy extends DSL with Loggable {
- lazy val policy = {
+
+ private var policies = {reloadPolicies}
+
+ lazy val policy = loadPolicyFromFile(policyFile)
- // Look for user configured policy first
- val userConf = MasterConfigurator.props.get(Keys.aquarium_policy) match {
- case Just(x) => x
- case _ => logger.info("Cannot find a user configured policy")
- "policy.yaml"
+ def policy(at: Date): Maybe[DSLPolicy] = Maybe {
+ policies.find {
+ a => a._1.from.before(at) &&
+ a._1.to.after(at)
+ } match {
+ case Some(x) => x._2
+ case None =>
+ throw new AccountingException("No valid policy for date: %s".format(at))
}
+ }
+
+ def policies(from: Date, to: Date): List[DSLPolicy] = {
+ policies.filter {
+ a => a._1.from.before(from) &&
+ a._1.to.after(to)
+ }.values.toList
+ }
+
+ def policies(t: Timeslot): List[DSLPolicy] = policies(t.from, t.to)
+
+ def loadPolicyFromFile(pol: File): DSLPolicy = {
- val pol = new File(userConf)
val stream = pol.exists() match {
case true =>
- logger.info("Using policy file %s".format(userConf))
+ logger.info("Using policy file %s".format(pol.getAbsolutePath))
new FileInputStream(pol)
case false =>
- logger.warn(("Cannot find policy file %s, " +
- "looking for default policy").format(userConf))
+ logger.warn(("Cannot find user configured policy file %s, " +
+ "looking for default policy").format(pol.getAbsolutePath))
getClass.getClassLoader.getResourceAsStream("policy.yaml") match {
case x: InputStream =>
- logger.warn("Using default policy, this is problably bad")
+ logger.warn("Using default policy, this is problably not what you want")
x
case null =>
logger.error("No valid policy file found, Aquarium will fail")
null
}
}
-
parse(stream)
}
+
+ private def policyFile: File =
+ MasterConfigurator.props.get(Keys.aquarium_policy) match {
+ case Just(x) => new File(x)
+ case _ => new File("/etc/aquarium/policy.yaml")
+ }
+
+ private def reloadPolicies(): Map[Timeslot, DSLPolicy] = synchronized {
+ //1. Load policies from db
+ val policies = MasterConfigurator.policyEventStore.loadPolicies(0)
+
+ //2. Check whether policy file has been updated
+ val latestPolicyChange = if (policies.isEmpty) 0 else policies.last.validFrom
+ val policyf = policyFile
+ var updated = false
+
+ if (policyf.exists) {
+ if (policyf.lastModified > latestPolicyChange) {
+ logger.info("Policy changed since last check, reloading")
+ updated = true
+ } else {
+ logger.info("Policy not changed since last check")
+ }
+ } else {
+ logger.warn("User specified policy file %s does not exist, " +
+ "using stored policy information".format(policyf.getAbsolutePath))
+ }
+
+ val toAdd = updated match {
+ case true =>
+ val ts = TimeHelpers.nowMillis
+ val toUpdate = policies.last.copy(validTo = ts)
+ val parsedNew = loadPolicyFromFile(policyf)
+ val yaml = parsedNew.toYAML
+ val newPolicy = PolicyEntry(CryptoUtils.sha1(yaml), ts, ts, yaml, ts + 1, -1)
+
+ MasterConfigurator.policyEventStore.updatePolicy(toUpdate)
+ MasterConfigurator.policyEventStore.storePolicy(newPolicy)
+
+ List(toUpdate, newPolicy)
+ case false => List()
+ }
+
+ policies.init.++(toAdd).foldLeft(Map[Timeslot, DSLPolicy]()){
+ (acc, p) =>
+ acc ++ Map(Timeslot(new Date(p.validFrom), new Date(p.validTo)) -> parse(p.policyYAML))
+ }
+ }
}
\ No newline at end of file