Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
VinceMacBuche committed Dec 13, 2016
1 parent 1687c0f commit 912dfef
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 97 deletions.
Expand Up @@ -40,45 +40,72 @@ package com.normation.rudder.datasources
import org.joda.time.DateTime
import org.joda.time.Seconds
import net.liftweb.common._
import scala.concurrent.duration.Duration

sealed trait DataSourceType {
def name : String
}

object DataSourceType {
def apply(name : String) : Box[DataSourceType] = {
if (name == ByNodeSourceType.name) {
Full(ByNodeSourceType)
} else {
Failure("not a valid source type name")
}
}
final case class HttpDataSourceType (
url : String
, headers : Map[String,String]
, httpMethod : String
, path : String
, requestMode : HttpRequestMode
, requestTimeOut : Duration
) extends DataSourceType {
val name = "http"
}

sealed trait HttpRequestMode {
def name : String
}
case object ByNodeSourceType extends DataSourceType {
final case object OneRequestByNode extends HttpRequestMode {
val name = "byNode"
}

case class AllNodesSourceType(
final case class OneRequestAllNodes(
matchingPath : String
, nodeAttribute : String
) extends DataSourceType {
val name = AllNodesSourceType.name
) extends HttpRequestMode {
val name = OneRequestAllNodes.name
}

object AllNodesSourceType {
object OneRequestAllNodes {
val name = "allNodes"
}
case class DataSourceName(value : String) extends AnyVal
final case class DataSourceName(value : String) extends AnyVal
final case class DataSourceId (value : String) extends AnyVal

sealed trait DataSourceSchedule {
def duration : Duration
}

final case class NoSchedule(
savedDuration : Duration
) extends DataSourceSchedule {
val duration = savedDuration
}

case class DataSource (
name : DataSourceName
, description: String
, sourceType : DataSourceType
, url : String
, headers : Map[String,String]
, httpMethod : String
, path : String
, frequency : Seconds
, lastUpdate : Option[DateTime]
, enabled : Boolean
final case class Scheduled(
duration : Duration
) extends DataSourceSchedule

final case class DataSourceRunParameters (
schedule : DataSourceSchedule
, onGeneration : Boolean
, onNewNode : Boolean
)

final case class DataSource (
id : DataSourceId
, name : DataSourceName
, sourceType : DataSourceType
, runParam : DataSourceRunParameters
, description : String
, lastUpdate : Option[DateTime]
, enabled : Boolean
, updateTimeOut : Duration
) {
val scope = "all"
}
Expand Up @@ -41,11 +41,11 @@ import net.liftweb.common.Box

trait DataSourceRepository {

def getAll : Box[Seq[DataSource]]
def getAll : Box[Map[DataSourceId,DataSource]]

def get(name : DataSourceName) : Box[Option[DataSource]]
def get(id : DataSourceId) : Box[Option[DataSource]]

def save(source : DataSource) : Box[DataSource]

def delete(source : DataSourceName) : Box[DataSource]
def delete(id : DataSourceId) : Box[DataSource]
}
Expand Up @@ -59,9 +59,7 @@ import com.normation.rudder.web.rest.node.MinimalDetailLevel
import com.normation.rudder.repository.FullActiveTechnique
import scala.language.implicitConversions
import com.normation.rudder.web.components.DateFormaterService
import com.normation.rudder.datasources.DataSource
import com.normation.rudder.datasources.ByNodeSourceType
import com.normation.rudder.datasources.AllNodesSourceType
import com.normation.rudder.datasources._

/**
* Centralize all function to serialize datas as valid answer for API Rest
Expand Down Expand Up @@ -594,23 +592,32 @@ case class RestDataSerializerImpl (

def serializeDataSource(source : DataSource): JValue = {
( ( "name" -> source.name.value )
~ ( "id" -> source.id.value )
~ ( "description" -> source.description )
~ ( "type" -> (
( "name" -> source.sourceType.name )
~ { source.sourceType match {
case ByNodeSourceType =>
JObject(Nil)
case allNodes : AllNodesSourceType =>
( ( "path" -> allNodes.matchingPath )
~ ( "attribute" -> allNodes.nodeAttribute )
)
} }
) )
~ ( "url" -> source.url )
~ ( "headers" -> source.headers )
~ ( "path" -> source.path )
~ ( "frequency" -> source.frequency.getSeconds )
case HttpDataSourceType(url,headers,method,path,mode,timeOut) =>
( ( "url" -> url )
~ ( "headers" -> headers )
~ ( "path" -> path )
~ ( "requestTimeout" -> timeOut.length )
~ ( "requestMode" ->
( ( "name" -> mode.name )
~ { mode match {
case OneRequestByNode =>
JObject(Nil)
case OneRequestAllNodes(subPath,nodeAttribute) =>
( ( "path" -> subPath)
~ ( "attribute" -> nodeAttribute)
)
} } )
) )
}
} )
)
~ ( "lastUpdate" -> source.lastUpdate.map { DateFormaterService.getFormatedDate(_)} . getOrElse("Never") )
~ ( "updateTimeOut" -> source.updateTimeOut.length )
~ ( "enabled" -> source.enabled )
)
}
Expand Down
Expand Up @@ -38,65 +38,122 @@
package com.normation.rudder.web.rest.compliance

import com.normation.rudder.web.rest.RestAPI
import com.normation.rudder.datasources.DataSourceName
import com.normation.rudder.datasources.DataSourceType
import org.joda.time.DateTime
import net.liftweb.common._
import com.normation.rudder.datasources.DataSource
import com.normation.rudder.datasources._
import com.normation.rudder.datasources.OneRequestAllNodes
import com.normation.rudder.datasources.OneRequestByNode
import org.joda.time.Seconds
import scala.concurrent.duration.Duration

trait DataSourceApi extends RestAPI {
val kind = "datasources"
}

sealed trait RestRequestMode[T <: HttpRequestMode]{
def name : String
def update(data : T) : T
def create() : T
}

final case object RestByNodeMode extends RestRequestMode[OneRequestByNode.type] {
def name = OneRequestByNode.name
def create = OneRequestByNode
def update(data : OneRequestByNode.type) = OneRequestByNode
}

final case class RestOneRequestMode(
matchingPath : Option[String]
, nodeAttribute : Option[String]
) extends RestRequestMode[OneRequestAllNodes] {
def name = OneRequestAllNodes.name
def create =
OneRequestAllNodes(
matchingPath.getOrElse("")
, nodeAttribute.getOrElse("")
)

def update(base : OneRequestAllNodes) =
OneRequestAllNodes(
matchingPath.getOrElse(base.matchingPath)
, nodeAttribute.getOrElse(base.nodeAttribute)
)
}

sealed trait RestSourceType[T <: DataSourceType] {
def name : String

def update(data : T) : T

def create() : T
}
case class RestHttpSourceType (
url : Option[String]
, headers : Option[Map[String,String]]
, httpMethod : Option[String]
, path : Option[String]
, requestMode : Option[RestRequestMode[HttpRequestMode]]
, requestTimeOut : Option[Duration]
) extends RestSourceType[HttpDataSourceType] {
val name = "http"

def update( base : HttpDataSourceType) = {
base.copy(
url = url.getOrElse(base.url)
, headers = headers.getOrElse(base.headers)
, httpMethod = httpMethod.getOrElse(base.httpMethod)
, path = path.getOrElse(base.path)
, requestMode = requestMode.map(_.update(base.requestMode)).getOrElse(base.requestMode)
, requestTimeOut = requestTimeOut.getOrElse(base.requestTimeOut)
)
}

def create = {
HttpDataSourceType(
url = url.getOrElse("")
, headers = headers.getOrElse(Map())
, httpMethod = httpMethod.getOrElse("GET")
, path = path.getOrElse("")
, requestMode = requestMode.map(_.create).getOrElse(OneRequestByNode)
, requestTimeOut = requestTimeOut.getOrElse(Duration.Inf)
)
}
}

case class RestDataSource (
name : DataSourceName
id : DataSourceId
, name : Option[DataSourceName]

, description: Option[String]
, sourceType : Option[DataSourceType]
, url : Option[String]
, headers : Option[Map[String,String]]
, path : Option[String]
, frequency : Option[Seconds]
, sourceType : Option[RestSourceType[DataSourceType]]
, enabled : Option[Boolean]
, timeOut : Option[Duration]
) {

def create() : Box[DataSource] = {

for {
sourceType <- Box(sourceType) ?~! "Source type must be defined when creating a data source"
desc = description.getOrElse("")
u = url.getOrElse("")
p = path.getOrElse("")
head = headers.getOrElse(Map())
freq = frequency.getOrElse(Seconds.seconds(60))
enab = enabled.getOrElse(false)

} yield {
DataSource(
name
, desc
, sourceType
, u
, head
, "get"
, p
, freq
, None
, enab
)
}
val defaultSourceType = RestHttpSourceType(None,None,None,None,None,None)

Full(DataSource(
id
, name.getOrElse(DataSourceName(""))
, sourceType.getOrElse(defaultSourceType).create()
, null // parameters
, description.getOrElse("")
, None
, enabled.getOrElse(false)
, timeOut.getOrElse(Duration.Inf)
))
}

def update(base : DataSource) : DataSource = {

val sType = sourceType.getOrElse(base.sourceType)
val desc = description.getOrElse(base.description)
val u = url.getOrElse(base.url)
val p = path.getOrElse(base.path)
val head = headers.getOrElse(base.headers)
val freq = frequency.getOrElse(base.frequency)
val enab = enabled.getOrElse(base.enabled)

base.copy(base.name, desc, sType, u, head, base.httpMethod, p, freq, base.lastUpdate, enab)
base.copy(
name = name.getOrElse(base.name)
, sourceType = sourceType.map(_.update(base.sourceType)).getOrElse(base.sourceType)
, description = description.getOrElse(base.description)
, enabled = enabled.getOrElse(base.enabled)
, updateTimeOut = timeOut.getOrElse(base.updateTimeOut)
)
}
}
Expand Up @@ -45,24 +45,23 @@ import com.normation.rudder.web.rest.RestUtils

class MemoryDataSourceRepository extends DataSourceRepository {

private[this] var sources : Map[DataSourceName,DataSource] = Map()
private[this] var sources : Map[DataSourceId,DataSource] = Map()

def getAll() = Full(sources.values.toSeq)
def getAll() = Full(sources)

def get(name : DataSourceName) : Box[Option[DataSource]]= Full(sources.get(name))
def get(id : DataSourceId) : Box[Option[DataSource]]= Full(sources.get(id))

def save(source : DataSource) = {
sources = sources + ((source.name,source))
println(sources.size)
sources = sources + ((source.id,source))
Full(source)
}
def delete(sourceName : DataSourceName) : Box[DataSource] = {
sources.get(sourceName) match {
def delete(id : DataSourceId) : Box[DataSource] = {
sources.get(id) match {
case Some(source) =>
sources = sources - (sourceName)
sources = sources - (id)
Full(source)
case None =>
Failure(s"Data source '${sourceName}' does not exists, and thus can't be deleted")
Failure(s"Data source '${id}' does not exists, and thus can't be deleted")
}
}
}
Expand All @@ -83,16 +82,16 @@ class DataSourceApiService(
}
}

def getSource(name : DataSourceName) : Box[JValue] = {
def getSource(id : DataSourceId) : Box[JValue] = {
for {
optSource <- dataSourceRepo.get(name)
source <- Box(optSource) ?~! s"Data source ${name} does not exist."
optSource <- dataSourceRepo.get(id)
source <- Box(optSource) ?~! s"Data source ${id} does not exist."
} yield {
restDataSerializer.serializeDataSource(source) :: Nil
}
}

def deleteSource(name : DataSourceName) : Box[JValue] = {
def deleteSource(name : DataSourceId) : Box[JValue] = {
for {
source <- dataSourceRepo.delete(name)
} yield {
Expand Down

0 comments on commit 912dfef

Please sign in to comment.