Skip to content

Commit

Permalink
Removing ContainerIdentifierService from API
Browse files Browse the repository at this point in the history
  • Loading branch information
atooni committed Mar 6, 2020
1 parent 1e1bb9e commit ec0fe3b
Show file tree
Hide file tree
Showing 17 changed files with 96 additions and 58 deletions.

This file was deleted.

Expand Up @@ -67,13 +67,11 @@ trait ContainerContext {
/**
* Provide access to encryption and decryption facilities, optionally secured with a secret file.
*/
@BeanProperty
val cryptoSupport : ContainerCryptoSupport

/**
* The application.conf, optionally modified with an overlay.
*/
@BeanProperty
val containerConfig : Config

/**
Expand All @@ -86,7 +84,6 @@ trait ContainerContext {
@BeanProperty
val uuid : String

@BeanProperty
val properties : Map[String, String]

/**
Expand Down
Expand Up @@ -8,10 +8,10 @@ import blended.security.crypto.{BlendedCryptoSupport, ContainerCryptoSupport}
import blended.updater.config.RuntimeConfig
import blended.util.logging.Logger
import com.typesafe.config.{Config, ConfigFactory}
import scala.collection.JavaConverters._

import scala.collection.JavaConverters._
import scala.beans.BeanProperty
import scala.util.Try
import scala.util.{Failure, Success, Try}

object AbstractContainerContextImpl {
val PROP_BLENDED_HOME = "blended.home"
Expand All @@ -23,19 +23,23 @@ abstract class AbstractContainerContextImpl extends ContainerContext {

private[this] lazy val log : Logger = Logger(getClass().getName())

private lazy val resolver : ContainerPropertyResolver = new ContainerPropertyResolver(this)
private lazy val resolver : ContainerPropertyResolver = {
// make sure all properties are resolved correctly
val msg : String = toString()
log.debug(s"Initializing resolver for [$msg]")
new ContainerPropertyResolver(Some(this))
}

/**
* Access to a blended resolver for config values
*/
override def resolveString(s: String, additionalProps: Map[String, Any]): Try[AnyRef] = Try {
override def resolveString(s: String, additionalProps: Map[String, Any]): Try[AnyRef] = {
resolver.resolve(s, additionalProps)
}

/**
* Provide access to encryption and decryption facilities, optionally secured with a secret file.
*/
@BeanProperty
override val cryptoSupport: ContainerCryptoSupport = {
import AbstractContainerContextImpl._

Expand Down Expand Up @@ -81,10 +85,11 @@ abstract class AbstractContainerContextImpl extends ContainerContext {
}
}

@BeanProperty
override lazy val properties : Map[String, String] = {

val cfg : Config = ConfigLocator.safeConfig(profileConfigDirectory, "blended.container.context.conf", ConfigFactory.empty(), this)
val propResolver : ContainerPropertyResolver = new ContainerPropertyResolver(None)

val cfg : Config = ConfigLocator.readConfigFile(new File(profileConfigDirectory, "blended.container.context.conf"), ConfigFactory.empty())

val mandatoryPropNames : Seq[String] = Option(System.getProperty(RuntimeConfig.Properties.PROFILE_PROPERTY_KEYS)) match {
case Some(s) => if (s.trim().isEmpty) Seq.empty else s.trim().split(",").toSeq
Expand All @@ -102,7 +107,13 @@ abstract class AbstractContainerContextImpl extends ContainerContext {
throw new RuntimeException(msg)
}

props
props.map{ case (k,v) =>
propResolver.resolve(v) match {
case Failure(t) => throw t
case Success(r) =>
k -> r.toString()
}
}
}

override def toString: String =
Expand Down
Expand Up @@ -21,13 +21,13 @@ object ConfigLocator {
private[this] val sysProps : Config = ConfigFactory.systemProperties()
private[this] val envProps : Config = ConfigFactory.systemEnvironment()

private[this] def readConfigFile(f : File, fallback : Config) : Config = ConfigFactory.parseFile(f)
private[internal] def readConfigFile(f : File, fallback : Config) : Config = ConfigFactory.parseFile(f)
.withFallback(fallback)
.withFallback(sysProps)
.withFallback(envProps)
.resolve()

private[this] def evaluatedConfig(f : File, fallback : Config, ctContext : ContainerContext) : Try[Config] = Try {
private[internal] def evaluatedConfig(f : File, fallback : Config, ctContext : ContainerContext) : Try[Config] = Try {

if (f.exists && f.isFile && f.canRead) {

Expand Down
Expand Up @@ -92,7 +92,6 @@ class ContainerContextImpl extends AbstractContainerContextImpl {
@BeanProperty
override lazy val profileConfigDirectory : String = new File(profileDirectory, CONFIG_DIR).getAbsolutePath

@BeanProperty
override lazy val containerConfig : Config = {
val sysProps = ConfigFactory.systemProperties()
val envProps = ConfigFactory.systemEnvironment()
Expand Down
Expand Up @@ -7,11 +7,12 @@ import blended.util.logging.Logger
import org.springframework.expression.Expression
import org.springframework.expression.spel.standard.SpelExpressionParser
import org.springframework.expression.spel.support.StandardEvaluationContext
import blended.util.RichTry._

import scala.collection.mutable
import scala.util.Try
import scala.util.{Failure, Success, Try}

class ContainerPropertyResolver(ctContext : ContainerContext) {
class ContainerPropertyResolver(ctCtxt : Option[ContainerContext]) {

private case class ExtractedElement(
prefix : String,
Expand All @@ -20,8 +21,8 @@ class ContainerPropertyResolver(ctContext : ContainerContext) {
modifier : String = ""
)

type Resolver = String => String
type Modifier = (String, String) => String
type Resolver = String => Try[String]
type Modifier = (String, String) => Try[String]

private[this] val log = Logger[ContainerPropertyResolver]

Expand Down Expand Up @@ -103,46 +104,52 @@ class ContainerPropertyResolver(ctContext : ContainerContext) {

// these are the valid modifiers in a resolver expression
private[this] val modifiers : Map[String, Modifier] = Map(
"upper" -> { case (s : String, _ : String) => s.toUpperCase() },
"upper" -> { case (s : String, _ : String) => Try { s.toUpperCase() } },

"lower" -> { case (s : String, _ : String) => s.toLowerCase() },
"lower" -> { case (s : String, _ : String) => Try { s.toLowerCase() } },

"capitalize" -> { case (s : String, _ : String) => s.capitalize },
"capitalize" -> { case (s : String, _ : String) => Try { s.capitalize } },

"right" -> {
case (s : String, param : String) =>
case (s : String, param : String) => Try {
val n = param.toInt
if (n >= s.length) s else s.takeRight(n)
}
},

"left" -> {
case (s : String, param : String) =>
case (s : String, param : String) => Try {
val n = param.toInt
if (n >= s.length) s else s.take(n)
}
},

"replace" -> {
case (s : String, param : String) =>
case (s : String, param : String) => Try {
val replace = param.split(":")
if (replace.length != 2) {
s
} else {
s.replaceAll(replace(0), replace(1))
}
}
}
)

private[this] val resolver : Map[String, Resolver] = Map(
ContainerContext.containerId -> (_ => ctContext.uuid)
)
ContainerContext.containerId -> { _ => ctCtxt match {
case None => Failure(new PropertyResolverException("Could not resolve container uuid"))
case Some(c) => Success(c.uuid)
}
})

private[this] def extractModifier(s : String) : Option[(Modifier, String)] = {
val pos = s.indexOf(":")
val (modName, params) = if (pos != -1) (s.substring(0, pos), s.substring(pos + 1)) else (s, "")
modifiers.get(modName).map { m => (m, params) }
}

private[this] def processRule(rule : String, additionalProps : Map[String, Any]) : String = {
private[this] def processRule(rule : String, additionalProps : Map[String, Any]) : Try[String] = {

log.trace(s"Processing rule [$rule]")

Expand All @@ -162,12 +169,12 @@ class ContainerPropertyResolver(ctContext : ContainerContext) {
case Some(m) => m
}

val props = Option(ctContext.properties).getOrElse(Map.empty)
val props : Map[String, String] = ctCtxt.map(_.properties).getOrElse(Map.empty)

// First, we resolve the rule from the environment vars or System properties
// The resolution is mandatory
var result : String = props.get(ruleName) match {
case Some(s) => s
val applyRules : Try[String] = props.get(ruleName) match {
case Some(s) => Success(s)
case None =>
Option(
additionalProps.getOrElse(
Expand All @@ -177,22 +184,25 @@ class ContainerPropertyResolver(ctContext : ContainerContext) {
)
)
) match {
case Some(s) => s.toString()
case Some(s) => Success(s.toString())
case None =>
resolver.get(ruleName) match {
case Some(r) => r(ruleName)
case None => throw new PropertyResolverException(s"Unable to resolve property [$rule]")
case None => Failure(new PropertyResolverException(s"Unable to resolve property [$rule]"))
}
}
}

// Then we apply the collected modifiers left to right to the resolved value
result = mods.foldLeft[String](result)((a, b) => b._1(a, b._2))
val result : Try[String] = mods.foldLeft[Try[String]](applyRules)( (current, value) => current match {
case f @ Failure(_) => f
case Success(s) => value._1(s, value._2)
})

result
}

def resolve(line : String, additionalProps : Map[String, Any] = Map.empty) : AnyRef = {
def resolve(line : String, additionalProps : Map[String, Any] = Map.empty) : Try[AnyRef] = Try {
// First we check if we have replacements in "Blended Style"

/**
Expand All @@ -204,17 +214,21 @@ class ContainerPropertyResolver(ctContext : ContainerContext) {
val e = extractVariableElement(line, resolveStartDelim, resolveEndDelim)
e.modifier match {
case "delayed" =>
resolve(e.prefix) + e.pattern + resolve(e.postfix)

case "encrypted" =>
val decrypted : String = ctContext.cryptoSupport.decrypt(e.pattern).get
resolve(e.prefix) + resolve(decrypted).toString() + resolve(e.postfix)
resolve(e.prefix).unwrap + e.pattern + resolve(e.postfix).unwrap

case "encrypted" => ctCtxt match {
case None =>
throw new PropertyResolverException(s"Could not decrypt config value [${e.pattern}]")
case Some(c) =>
val decrypted : String = c.cryptoSupport.decrypt(e.pattern).get
resolve(e.prefix).unwrap.toString() + resolve(decrypted).unwrap.toString() + resolve(e.postfix).unwrap.toString()
}

case _ =>
// First we resolve the inner expression to resolve any nested expressions
val inner = resolve(e.pattern, additionalProps).toString
val inner = resolve(e.pattern, additionalProps).unwrap.toString
// then we resolve the entire line with the inner expression resolved
resolve(e.prefix + processRule(inner, additionalProps) + e.postfix, additionalProps)
resolve(e.prefix + processRule(inner, additionalProps).unwrap + e.postfix, additionalProps).unwrap

}
} else {
Expand All @@ -226,7 +240,7 @@ class ContainerPropertyResolver(ctContext : ContainerContext) {
if (e.prefix.isEmpty && e.postfix.isEmpty) {
evaluate(e.pattern, additionalProps)
} else {
resolve(e.prefix + evaluate(e.pattern, additionalProps) + e.postfix, additionalProps)
resolve(e.prefix + evaluate(e.pattern, additionalProps).toString() + e.postfix, additionalProps).unwrap
}
}
}
Expand All @@ -242,13 +256,15 @@ class ContainerPropertyResolver(ctContext : ContainerContext) {
context.registerFunction(m.getName(), m)
}

context.setRootObject(ctContext)
ctCtxt.foreach{ c =>
context.setRootObject(c)
context.setVariable("ctCtxt", c)
}

additionalProps.foreach {
case (k, v) =>
context.setVariable(k, v)
}
context.setVariable("ctCtxt", ctContext)

val exp = parseExpression(line).get

Expand Down
Expand Up @@ -6,4 +6,9 @@
version: "2.2.0"
typeA : "A"
typeB : "B"
}

blended {
country= "$[[COUNTRY]]"
demoProp="myProperty"
}
}
Expand Up @@ -11,7 +11,7 @@ class ConfigLocatorSpec extends LoggingFreeSpec
with Matchers {

private val cfgDir : String = BlendedTestSupport.projectTestOutput
System.setProperty(RuntimeConfig.Properties.PROFILE_PROPERTY_KEYS, "foo,bar,FOO,num,version,typeA,typeB")
System.setProperty(RuntimeConfig.Properties.PROFILE_PROPERTY_KEYS, "foo,bar,FOO,num,version,typeA,typeB,blended.country,blended.demoProp")
System.setProperty("blended.home", BlendedTestSupport.projectTestOutput)
val ctCtxt : ContainerContext = new ContainerContextImpl()

Expand Down
Expand Up @@ -4,25 +4,35 @@ import blended.container.context.api.ContainerContext
import blended.testsupport.BlendedTestSupport
import blended.testsupport.scalatest.LoggingFreeSpec
import blended.updater.config.RuntimeConfig
import blended.util.logging.Logger
import org.scalatest.Matchers
import blended.util.RichTry._

class ContainerContextImplSpec extends LoggingFreeSpec
with Matchers {

private val log : Logger = Logger[ContainerContextImplSpec]

"The container context implementation should" - {

"initialize correctly" in {

System.setProperty(RuntimeConfig.Properties.PROFILE_PROPERTY_KEYS, "foo,bar")
System.setProperty("COUNTRY", "cc")
System.setProperty(RuntimeConfig.Properties.PROFILE_PROPERTY_KEYS, "foo,bar,FOO,num,version,typeA,typeB,blended.country,blended.demoProp")
System.setProperty("blended.home", BlendedTestSupport.projectTestOutput)
val ctContext : ContainerContext = new ContainerContextImpl()

ctContext.properties should have size(2)
log.info(s"Container Context : [$ctContext]")

ctContext.properties should have size(9)
ctContext.properties.get("foo") should be (Some("bar"))
ctContext.properties.get("bar") should be (Some("test"))
ctContext.properties.get("blended.country") should be (Some("cc"))

ctContext.containerDirectory should be (BlendedTestSupport.projectTestOutput)
ctContext.uuid should be ("context")

ctContext.resolveString("$[[" + ContainerContext.containerId + "]]").unwrap should be(ctContext.uuid)
}
}

Expand Down
Expand Up @@ -11,7 +11,8 @@ import scala.util.control.NonFatal
class PropertyResolverSpec extends FreeSpec
with Matchers {

System.setProperty(RuntimeConfig.Properties.PROFILE_PROPERTY_KEYS, "foo,bar,FOO,num,version,typeA,typeB")
System.setProperty("COUNTRY", "cc")
System.setProperty(RuntimeConfig.Properties.PROFILE_PROPERTY_KEYS, "foo,bar,FOO,num,version,typeA,typeB,blended.country,blended.demoProp")
System.setProperty("blended.home", BlendedTestSupport.projectTestOutput)
val ctCtxt : ContainerContext = new ContainerContextImpl()

Expand Down
Expand Up @@ -28,7 +28,7 @@ class MgmtMockClients(config : Config) {
@BeanProperty override val profileDirectory: String = containerDirectory
@BeanProperty override val profileConfigDirectory: String = containerDirectory
@BeanProperty override val containerHostname: String = "localhost"
@BeanProperty override val containerConfig: TSConfig = ConfigFactory.empty()
override val containerConfig: TSConfig = ConfigFactory.empty()
}

implicit val system : ActorSystem = ActorSystem("MgmtMockClients")
Expand Down
Expand Up @@ -29,7 +29,7 @@ class ScepAppContainerContext(baseDir : String) extends AbstractContainerContext

@BeanProperty override lazy val containerHostname : String = "localhost"

@BeanProperty override lazy val containerConfig : Config = {
override lazy val containerConfig : Config = {
val sys = new Properties()
sys.putAll(System.getProperties())
val sysProps = Parseable.newProperties(sys, ConfigParseOptions.defaults().setOriginDescription("system properties")).parse()
Expand Down

This file was deleted.

0 comments on commit ec0fe3b

Please sign in to comment.