Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
ElaadF committed Mar 18, 2020
1 parent e1996c2 commit bcd6080
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.normation.plugins.RudderPluginModule
import com.normation.plugins.scaleoutrelay.ScalaOutRelayPluginDef
import com.normation.plugins.scaleoutrelay.CheckRudderPluginEnableImpl
import com.normation.plugins.scaleoutrelay.ScaleOutRelayAgentSpecificGeneration
import com.normation.plugins.scaleoutrelay.api.ScaleOutRelayApiImpl

/*
* Actual configuration of the plugin logic
Expand All @@ -53,6 +54,8 @@ object ScalaOutRelayConf extends RudderPluginModule {

lazy val pluginDef = new ScalaOutRelayPluginDef(ScalaOutRelayConf.pluginStatusService)

lazy val api = new ScaleOutRelayApiImpl(RudderConfig.restExtractorService)

// add policy generation for AIX nodes
RudderConfig.agentRegister.addAgentLogic(new ScaleOutRelayAgentSpecificGeneration(pluginStatusService))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@

package com.normation.plugins.scaleoutrelay

import bootstrap.liftweb.Boot
import bootstrap.rudder.plugin.ScalaOutRelayConf
import com.normation.plugins._
import com.normation.rudder.AuthorizationType.Administration
import com.normation.rudder.rest.EndpointSchema
import com.normation.rudder.rest.lift.LiftApiModuleProvider
import net.liftweb.http.ClasspathTemplates
import net.liftweb.sitemap.Loc.{LocGroup, Template, TestAccess}
import net.liftweb.sitemap.Menu

class ScalaOutRelayPluginDef(override val status: PluginStatus) extends DefaultPluginDef {

Expand All @@ -48,4 +56,16 @@ class ScalaOutRelayPluginDef(override val status: PluginStatus) extends DefaultP
def oneTimeInit : Unit = {}

val configFiles = Seq()

override def apis: Option[LiftApiModuleProvider[_ <: EndpointSchema]] = Some(ScalaOutRelayConf.api)


override def pluginMenuEntry: Option[Menu] = {
Some(Menu("scaleoutrelay", <span>Scale Out Relay</span>) /
"secure" / "plugins" / "scaleoutrelay"
>> LocGroup("pluginsGroup")
>> TestAccess ( () => Boot.userIsAllowed("/secure/index", Administration.Read))
>> Template(() => ClasspathTemplates("template" :: "ScaleOutRelay" :: Nil ) openOr <div>Template not found</div>)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package com.normation.plugins.scaleoutrelay

import bootstrap.liftweb.RudderConfig
import com.normation.cfclerk.domain.TechniqueVersion
import com.normation.errors.IOResult
import com.normation.errors._
import com.normation.eventlog.EventActor
import com.normation.eventlog.ModificationId
import com.normation.inventory.domain.NodeId
import com.normation.rudder.domain.nodes.Node
import com.normation.rudder.domain.nodes.NodeGroup
import com.normation.rudder.domain.nodes.NodeGroupCategoryId
import com.normation.rudder.domain.nodes.NodeGroupId
import com.normation.rudder.domain.nodes.NodeInfo
import com.normation.rudder.domain.policies._
import com.normation.rudder.domain.queries._
import com.normation.rudder.rule.category.RuleCategoryId
import net.liftweb.common.EmptyBox
import net.liftweb.common.Failure
import net.liftweb.common.Full
import zio.ZIO


object ScaleOutRelayService {
val SYSTEM_GROUPS = "SystemGroups"
val DISTRIBUTE_POLICY = "distributePolicy"
val COMMON = "common"

private val nodeInfosService = RudderConfig.nodeInfoService
private val woLDAPNodeGroupRepository = RudderConfig.woNodeGroupRepository
private val woLDAPNodeRepository = RudderConfig.woNodeRepository
private val woDirectiveRepository = RudderConfig.woDirectiveRepository
private val woRuleRepository = RudderConfig.woRuleRepository
private val uuidGen = RudderConfig.stringUuidGenerator
private val policyServerManagementService = RudderConfig.policyServerManagementService
private val removeNodeService = RudderConfig.removeNodeService

def promoteNodeToRelay(uuid: NodeId, actor: EventActor, reason:Option[String]): ZIO[Any, RudderError, NodeInfo] = {
val modId = ModificationId(uuidGen.newUuid)
for {
nodeInfos <- getNodeToPromote(uuid)
updatedNode = createNodeToPolicyServerType(nodeInfos)
_ <- removeNodeService.removeNode(nodeInfos.node.id, modId, actor).toIO
newRelay <- createRelayFromNode(updatedNode, modId, actor, reason)
} yield {
newRelay
}
}

private[scaleoutrelay] def createRelayFromNode(nodeInf: NodeInfo, modId: ModificationId, actor: EventActor, reason:Option[String])= {
for {
commonDirective <- createCommonDirective(nodeInf).toIO

directDistribPolicy = createDirectiveDistributePolicy(nodeInf.node.id)
ruleTarget = createPolicyServer(nodeInf.node.id)
nodeGroup = createNodeGroup(nodeInf.node.id)
ruleDistribPolicy = createRuleDistributePolicy(nodeInf.node.id)
ruleSetup = createRuleSetup(nodeInf.node.id)

categoryId = NodeGroupCategoryId(SYSTEM_GROUPS)
activeTechniqueId = ActiveTechniqueId(DISTRIBUTE_POLICY)
activeTechniqueIdCommon = ActiveTechniqueId(COMMON)

_ <- woLDAPNodeRepository.createNode(nodeInf.node, modId, actor, reason)
_ <- woLDAPNodeGroupRepository.createPolicyServerTarget(ruleTarget, modId, actor, reason)
_ <- woLDAPNodeGroupRepository.create(nodeGroup, categoryId, modId, actor, reason)
_ <- woDirectiveRepository.saveSystemDirective(activeTechniqueId, directDistribPolicy, modId, actor, reason)
_ <- woDirectiveRepository.saveSystemDirective(activeTechniqueIdCommon, commonDirective, modId, actor, reason)
_ <- woRuleRepository.create(ruleSetup, modId, actor, reason)
_ <- woRuleRepository.create(ruleDistribPolicy, modId, actor, reason)
} yield {
nodeInf
}
}

private[scaleoutrelay] def getNodeToPromote(uuid: NodeId): IOResult[NodeInfo] = {
nodeInfosService.getNodeInfo(uuid) match {
case Full(nodeOpt) => nodeOpt.notOptional(s"Node with UUID ${uuid.value} is missing and can not be upgraded to relay")
case eb: EmptyBox => eb.toIO
}
}

private[scaleoutrelay] def createNodeToPolicyServerType(nodeInf: NodeInfo) = {
val newNode = nodeInf.node.copy(id = nodeInf.node.id, name = nodeInf.node.id.value, isSystem = true, isPolicyServer = true)
nodeInf.copy(node = newNode)
}

private[scaleoutrelay] def createPolicyServer(uuid: NodeId) = {
PolicyServerTarget(uuid)
}

private[scaleoutrelay] def createNodeGroup(uuid: NodeId) = {
val objectType = ObjectCriterion("node", Seq(Criterion("policyServerId", StringComparator, None),Criterion("agentName", AgentComparator, None)))
val attribute = Criterion("agentName", StringComparator)
val comparator = Equals
val value = "cfengine"

val attribute2 = Criterion("policyServerId", StringComparator)
val comparator2 = Equals
val value2 = uuid.value
NodeGroup(
NodeGroupId(s"hasPolicyServer-${uuid.value}")
, s"All classic Nodes managed by ${uuid.value} policy server"
, s"All classic Nodes known by Rudder directly connected to the ${uuid.value} server. This group exists only as internal purpose and should not be used to configure Nodes."
, Some(
Query(
NodeAndPolicyServerReturnType
, And
, List(CriterionLine(objectType, attribute, comparator, value)
, CriterionLine(objectType, attribute2, comparator2, value2))
)
)
, true
, Set()
, true
, true
)
}

private[scaleoutrelay] def createDirectiveDistributePolicy(uuid: NodeId) = {
Directive(
DirectiveId(s"${uuid.value}-distributePolicy")
, TechniqueVersion("1.0")
, Map()
, s"${uuid.value}-Distribute Policy"
, "Distribute policy - Technical"
, None
, ""
, 0
, true
, true
, Tags(Set.empty)
)
}

private[scaleoutrelay] def createCommonDirective(nodeInf: NodeInfo) = {
for {
authorizedNetworks <- policyServerManagementService.getAuthorizedNetworks(nodeInf.node.id)
} yield {
val parameters =
Map (
"OWNER" -> Seq("${rudder.node.admin}")
, "UUID" -> Seq("${rudder.node.id}")
, "POLICYSERVER" -> Seq(nodeInf.hostname)
, "POLICYSERVER_ID" -> Seq(nodeInf.policyServerId.value)
, "POLICYSERVER_ADMIN" -> Seq("root")
, "ALLOWEDNETWORK" -> authorizedNetworks
)
Directive(
DirectiveId(s"common-${nodeInf.node.id.value}")
, TechniqueVersion("1.0")
, parameters
, s"Common-${nodeInf.node.id.value}"
, "Common - Technical"
, None
, ""
, 0
, true
, true
, Tags(Set.empty)
)
}
}

private[scaleoutrelay] def createRuleDistributePolicy(uuid: NodeId) = {
Rule(
RuleId(s"${uuid.value}-DP")
, s"${uuid.value}-distributePolicy"
, RuleCategoryId("rootRuleCategory")
, Set(PolicyServerTarget(uuid))
, Set(DirectiveId(s"${uuid.value}-distributePolicy"))
, "Distribute Policy - Technical"
, "This rule allows to distribute policies to nodes"
, true
, true
)
}

private[scaleoutrelay] def createRuleSetup(uuid: NodeId) = {
Rule(
RuleId(s"hasPolicyServer-${uuid.value}")
, s"Rudder system policy: basic setup (common)-${uuid.value}"
, RuleCategoryId("rootRuleCategory")
, Set(GroupTarget(NodeGroupId(s"hasPolicyServer-${uuid.value}")))
, Set(DirectiveId(s"common-${uuid.value}"))
, "Common - Technical"
, "This is the basic system rule which all nodes must have."
, true
, true
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.normation.plugins.scaleoutrelay.api


import com.normation.box._
import com.normation.eventlog.EventActor
import com.normation.inventory.domain.NodeId
import com.normation.plugins.scaleoutrelay.ScaleOutRelayService
import com.normation.rudder.api.HttpAction.POST
import com.normation.rudder.rest.EndpointSchema.syntax._
import com.normation.rudder.rest._
import com.normation.rudder.rest.lift.DefaultParams
import com.normation.rudder.rest.lift.LiftApiModule
import com.normation.rudder.rest.lift.LiftApiModuleProvider
import net.liftweb.common.Box
import net.liftweb.common.EmptyBox
import net.liftweb.common.Full
import net.liftweb.http.LiftResponse
import net.liftweb.http.Req
import net.liftweb.json.JsonAST.JValue
import net.liftweb.json.NoTypeHints
import sourcecode.Line
import com.normation.eventlog.EventActor
import com.normation.inventory.domain.NodeId
import com.normation.plugins.scaleoutrelay.ScaleOutRelayService
import com.normation.rudder.api.HttpAction.POST
import com.normation.rudder.repository.json.DataExtractor.CompleteJson
import com.normation.rudder.rest.EndpointSchema.syntax._
import com.normation.rudder.rest.RestUtils.toJsonError
import com.normation.rudder.rest.RestUtils.toJsonResponse
import com.normation.rudder.rest._
import com.normation.rudder.rest.lift.DefaultParams
import com.normation.rudder.rest.lift.LiftApiModule
import com.normation.rudder.rest.lift.LiftApiModuleProvider
import net.liftweb.common.Box
import net.liftweb.common.Full
import net.liftweb.http.LiftResponse
import net.liftweb.http.Req
import net.liftweb.json.JsonAST.JString
import net.liftweb.json.JsonAST.JValue
import net.liftweb.json.JsonDSL._
import net.liftweb.json.NoTypeHints
import sourcecode.Line



sealed trait ScaleOutRelayApi extends EndpointSchema with GeneralApi with SortIndex
object ScaleOutRelayApi extends ApiModuleProvider[ScaleOutRelayApi] {

final case object PromoteNodeToRelay extends ScaleOutRelayApi with OneParam with StartsAtVersion10 {
val z = implicitly[Line].value
val description = "Promote a node to relay"
val (action, path) = POST / "scaleoutrelay" / "promote" / "{nodeId}"
}

override def endpoints: List[ScaleOutRelayApi] = ca.mrvisser.sealerate.values[ScaleOutRelayApi].toList.sortBy( _.z )
}

class ScaleOutRelayApiImpl(
restExtractorService: RestExtractorService
) extends LiftApiModuleProvider[ScaleOutRelayApi] {

api =>

implicit val formats = net.liftweb.json.Serialization.formats((NoTypeHints))
override def schemas = ScaleOutRelayApi

override def getLiftEndpoints(): List[LiftApiModule] = {
ScaleOutRelayApi.endpoints.map {
case ScaleOutRelayApi.PromoteNodeToRelay => PromoteNodeToRelay
}.toList
}

def response(function: Box[JValue], req: Req, errorMessage: String, id: Option[String], dataName: String)(implicit action: String): LiftResponse = {
RestUtils.response(restExtractorService, dataName, id)(function, req, errorMessage)
}

object PromoteNodeToRelay extends LiftApiModule {
val schema = ScaleOutRelayApi.PromoteNodeToRelay
val restExtractor = api.restExtractorService

def process(version: ApiVersion, path: ApiPath, nodeId: String, req: Req, params: DefaultParams, authz: AuthzToken): LiftResponse = {
val response = for {
node <- ScaleOutRelayService.promoteNodeToRelay(NodeId(nodeId), EventActor("rudder"), Some(s"Promote node ${nodeId} to relay")).toBox
} yield {
node
}

response match {
case Full(node) =>
toJsonResponse(None,node.id.value)("promoteToRelay",true)
case eb: EmptyBox =>
val message = (eb ?~ (s"Error when trying to promote mode $nodeId")).msg
println(eb)
toJsonError(None, message)("promoteToRelay",true)
}

}
}
}

0 comments on commit bcd6080

Please sign in to comment.