Skip to content

Commit

Permalink
Fixes #5843: Add user defined (via API) node properties
Browse files Browse the repository at this point in the history
  • Loading branch information
fanf committed Nov 28, 2014
1 parent c0282dc commit d8ee35b
Show file tree
Hide file tree
Showing 29 changed files with 651 additions and 186 deletions.
9 changes: 8 additions & 1 deletion rudder-core/src/main/resources/ldap/rudder.schema
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,13 @@ attributetype ( RudderAttributes:351
EQUALITY caseExactMatch
SUBSTR caseIgnoreSubstringsMatch )

attributetype ( RudderAttributes:352
NAME 'serializedNodeProperty'
DESC 'Serialization of a node property, typically a key=value pair)'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
EQUALITY caseExactMatch
SUBSTR caseIgnoreSubstringsMatch )

#######################################################
################ Object Classes ######################
#######################################################
Expand All @@ -402,7 +409,7 @@ objectclass ( RudderObjectClasses:1
SUP top
STRUCTURAL
MUST ( nodeId $ cn $ isSystem $ isBroken)
MAY ( description $ serializedAgentRunInterval ) )
MAY ( description $ serializedNodeProperty $ serializedAgentRunInterval ) )

objectclass ( RudderObjectClasses:2
NAME 'rudderPolicyServer'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ object RudderLDAPConstants extends Loggable {
val A_SERIALIZED_AGENT_RUN_INTERVAL = "serializedAgentRunInterval"


val A_NODE_PROPERTY = "serializedNodeProperty"


val A_PRIORITY = "directivePriority"
val A_LONG_DESCRIPTION = "longDescription"
val A_SERIAL = "serial"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ package com.normation.rudder.domain.nodes
import com.normation.inventory.domain.NodeId
import com.normation.utils.HashcodeCaching
import com.normation.rudder.reports.ReportingConfiguration
import net.liftweb.json.JsonAST.JObject
import org.joda.time.DateTime

/**
* The entry point for a REGISTERED node in Rudder.
Expand All @@ -45,11 +47,50 @@ import com.normation.rudder.reports.ReportingConfiguration
*
*/
case class Node(
id : NodeId
, name : String
, description : String
, isBroken : Boolean
, isSystem : Boolean
, isPolicyServer : Boolean
id : NodeId
, name : String
, description : String
, isBroken : Boolean
, isSystem : Boolean
, isPolicyServer : Boolean
, creationDate : DateTime
, nodeReportingConfiguration: ReportingConfiguration
, properties : Seq[NodeProperty]
) extends HashcodeCaching



case class NodeProperty(name: String, value: String)

object JsonSerialisation {

import net.liftweb.json.JsonDSL._
import net.liftweb.json._


implicit class JsonNodeProperty(x: NodeProperty) {
def toLdapJson(): JObject = (
( "name" , x.name )
~ ( "value" , x.value )
)
}

implicit class JsonNodeProperties(x: Seq[NodeProperty]) {
import net.liftweb.json.Serialization.write
implicit val formats = DefaultFormats

def toApiJson(): JObject = {
val map = (x.map { case NodeProperty(k,v) => (k,v) }).toMap
map2jvalue(map)
}
}

def unserializeLdapNodeProperty(value:String): NodeProperty = {
import net.liftweb.json.JsonParser._
implicit val formats = DefaultFormats

parse(value).extract[NodeProperty]
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ import BuildFilter._
import scala.collection.{SortedMap,SortedSet}
import com.normation.rudder.services.queries.SpecialFilter
import com.normation.utils.HashcodeCaching

import com.normation.rudder.domain.NodeDit
import com.normation.rudder.domain.RudderLDAPConstants.A_NODE_PROPERTY

/*
* Here we define all data needed logic by the to create the search
Expand All @@ -69,7 +70,7 @@ case object QueryMachineDn extends DnType
case object QueryNodeDn extends DnType
case object QuerySoftwareDn extends DnType

class DitQueryData(dit:InventoryDit) {
class DitQueryData(dit:InventoryDit, nodeDit: NodeDit) {
private val peObjectCriterion = ObjectCriterion(OC_PE, Seq(
// Criterion(A_MACHINE_UUID, StringComparator),
// Criterion(A_MACHINE_DN, StringComparator), //we don't want to search on that
Expand Down Expand Up @@ -224,10 +225,10 @@ class DitQueryData(dit:InventoryDit) {
)),
ObjectCriterion(A_EV, Seq(
Criterion("name.value", JsonComparator(A_EV,"=") )
))/*,
ObjectCriterion(OC_GROUP_OF_DNS,Seq(
Criterion(A_NAME,GroupOfDnsComparator)
))*/ // Hidding a code difficult to import
))
, ObjectCriterion(A_NODE_PROPERTY, Seq(
Criterion("name.value", JsonComparator(A_NODE_PROPERTY,"=") )
))
)

val criteriaMap : SortedMap[String,ObjectCriterion] = SortedMap[String,ObjectCriterion]() ++ (criteriaSet map { crit => (crit.objectType,crit) })
Expand Down Expand Up @@ -281,6 +282,7 @@ case class LDAPObjectType(
"software" -> LDAPObjectType(dit.SOFTWARE.dn, One, LDAPObjectTypeFilter(ALL), None, DNJoin),
"node" -> LDAPObjectType(dit.NODES.dn, One, LDAPObjectTypeFilter(ALL), None, DNJoin),
"nodeAndPolicyServer" -> LDAPObjectType(dit.NODES.dn, One, LDAPObjectTypeFilter(ALL), None, DNJoin),
"serializedNodeProperty" -> LDAPObjectType(nodeDit.NODES.dn, One, LDAPObjectTypeFilter(ALL),None, DNJoin),
"networkInterfaceLogicalElement" -> LDAPObjectType(dit.NODES.dn, Sub, LDAPObjectTypeFilter(IS(OC_NET_IF)), None, ParentDNJoin),
"process" -> LDAPObjectType(dit.NODES.dn, One, LDAPObjectTypeFilter(ALL), None, DNJoin),
"virtualMachineLogicalElement" -> LDAPObjectType(dit.NODES.dn, Sub, LDAPObjectTypeFilter(IS(OC_VM_INFO)), None, ParentDNJoin),
Expand Down Expand Up @@ -308,6 +310,7 @@ case class LDAPObjectType(
"software" -> QuerySoftwareDn,
"node" -> QueryNodeDn,
"nodeAndPolicyServer" -> QueryNodeDn,
"serializedNodeProperty" -> QueryNodeDn,
"networkInterfaceLogicalElement" -> QueryNodeDn,
"fileSystemLogicalElement" -> QueryNodeDn,
"process" -> QueryNodeDn,
Expand All @@ -334,6 +337,7 @@ case class LDAPObjectType(
"software" -> DNJoin,
"node" -> DNJoin,
"nodeAndPolicyServer" -> DNJoin,
"serializedNodeProperty" -> DNJoin,
"networkInterfaceLogicalElement" -> ParentDNJoin,
"fileSystemLogicalElement" -> ParentDNJoin,
"process" -> DNJoin,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import com.normation.rudder.domain.RudderLDAPConstants._
import com.normation.rudder.domain.{NodeDit,RudderDit}
import com.normation.rudder.domain.servers._
import com.normation.rudder.domain.nodes.Node
import com.normation.rudder.domain.nodes.JsonSerialisation._
import com.normation.rudder.domain.queries._
import com.normation.rudder.domain.policies._
import com.normation.rudder.domain.nodes._
Expand Down Expand Up @@ -108,9 +109,13 @@ class LDAPEntityMapper(
case Some(interval) => entry +=! (A_SERIALIZED_AGENT_RUN_INTERVAL, Printer.compact(JsonAST.render(serializeAgentRunInterval(interval))))
case _ =>
}

entry +=! (A_NODE_PROPERTY, node.properties.map(x => Printer.compact(JsonAST.render(x.toLdapJson))):_* )

entry
}


def serializeAgentRunInterval(agentInterval: AgentRunInterval) : JObject = {
import net.liftweb.json.JsonDSL._
( "overrides" , agentInterval.overrides ) ~
Expand All @@ -131,21 +136,21 @@ class LDAPEntityMapper(
if(e.isA(OC_RUDDER_NODE)||e.isA(OC_POLICY_SERVER_NODE)) {
//OK, translate
for {
id <- nodeDit.NODES.NODE.idFromDn(e.dn) ?~! s"Bad DN found for a Node: ${e.dn}"
name = e(A_NAME).getOrElse("")
description = e(A_DESCRIPTION).getOrElse("")
agentRunInterval = e(A_SERIALIZED_AGENT_RUN_INTERVAL).map(unserializeAgentRunInterval(_))
id <- nodeDit.NODES.NODE.idFromDn(e.dn) ?~! s"Bad DN found for a Node: ${e.dn}"
date <- e.getAsGTime(A_OBJECT_CREATION_DATE) ?~! s"Can not find mandatory attribute '${A_OBJECT_CREATION_DATE}' in entry"
} yield {
Node(
id
, name
, description
, e(A_NAME).getOrElse("")
, e(A_DESCRIPTION).getOrElse("")
, e.getAsBoolean(A_IS_BROKEN).getOrElse(false)
, e.getAsBoolean(A_IS_SYSTEM).getOrElse(false)
, e.isA(OC_POLICY_SERVER_NODE)
, date.dateTime
, ReportingConfiguration(
agentRunInterval
)
e(A_SERIALIZED_AGENT_RUN_INTERVAL).map(unserializeAgentRunInterval(_))
)
, e.valuesFor(A_NODE_PROPERTY).map(unserializeLdapNodeProperty(_)).toSeq
)
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import com.unboundid.ldap.sdk.{DN,Filter}
import com.normation.ldap.sdk._
import com.normation.rudder.services.user.PersonIdentService
import com.normation.rudder.domain.NodeDit
import com.normation.rudder.services.nodes.NodeInfoServiceImpl


class WoLDAPNodeRepository(
Expand All @@ -65,9 +66,10 @@ class WoLDAPNodeRepository(
* If the node is a system one, the methods fails.
*/
def update(node:Node, modId: ModificationId, actor:EventActor, reason:Option[String]) : Box[Node] = {
import NodeInfoServiceImpl.{nodeInfoAttributes => attrs}
repo.synchronized { for {
con <- ldap
existingEntry <- con.get(nodeDit.NODES.NODE.dn(node.id.value)) ?~! s"Cannot update node with id ${node.id.value} : there is no node with that id"
existingEntry <- con.get(nodeDit.NODES.NODE.dn(node.id.value), attrs:_*) ?~! s"Cannot update node with id ${node.id.value} : there is no node with that id"
oldNode <- mapper.entryToNode(existingEntry) ?~! "Error when transforming LDAP entry into a node for id ${node.id.value} . Entry: ${existingEntry}"
// here goes the check that we are not updating policy server
nodeEntry = mapper.nodeToEntry(node)
Expand All @@ -78,4 +80,4 @@ class WoLDAPNodeRepository(
} }
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import com.normation.rudder.domain.RudderDit
import com.normation.rudder.domain.NodeDit
import net.liftweb.common._
import net.liftweb.util.Helpers._
import com.normation.rudder.domain.nodes.NodeInfo
import com.normation.rudder.domain.nodes.{NodeInfo, Node}
import com.normation.rudder.domain.RudderLDAPConstants._
import com.normation.inventory.ldap.core.LDAPConstants._
import com.normation.rudder.domain.Constants._
Expand Down Expand Up @@ -79,19 +79,15 @@ trait NodeInfoService {
*/
def getNodeInfo(nodeId: NodeId) : Box[NodeInfo]

/**
* Return a seq of NodeInfo from a seq of NodeId.
* If any of them fails, then we return Failure
* @param nodeId
* @return
*/
// def find(nodeIds: Seq[NodeId]) : Box[Seq[NodeInfo]]


/**
* Get all node ids
* Get the node (not inventory).
* Most of the info are also in node info,
* but for some specific case (nodeProperties for ex),
* we need them.
*/
// def getAllIds() : Box[Seq[NodeId]]
def getNode(nodeId: NodeId): Box[Node]


/**
* Get all node infos.
Expand All @@ -102,12 +98,6 @@ trait NodeInfoService {
*/
def getAll() : Box[Map[NodeId, NodeInfo]]

/**
* Get all "simple" node ids (i.e, all user nodes,
* for example, NOT policy servers)
*/
// def getAllUserNodeIds() : Box[Seq[NodeId]]

/**
* Get all systen node ids, for example
* policy server node ids.
Expand All @@ -121,16 +111,26 @@ object NodeInfoServiceImpl {
}

class NodeInfoServiceImpl(
nodeDit : NodeDit,
rudderDit:RudderDit,
inventoryDit:InventoryDit,
ldap:LDAPConnectionProvider[RoLDAPConnection],
ldapMapper:LDAPEntityMapper,
inventoryMapper:InventoryMapper,
inventoryDitService:InventoryDitService
nodeDit : NodeDit
, rudderDit : RudderDit
, inventoryDit : InventoryDit
, ldap : LDAPConnectionProvider[RoLDAPConnection]
, ldapMapper : LDAPEntityMapper
, inventoryMapper : InventoryMapper
, inventoryDitService: InventoryDitService
) extends NodeInfoService with Loggable {
import NodeInfoServiceImpl._

def getNode(nodeId: NodeId): Box[Node] = {
for {
con <- ldap
entry <- con.get(nodeDit.NODES.NODE.dn(nodeId.value), nodeInfoAttributes:_*) ?~! s"Node with ID '${nodeId.value}' was not found"
node <- ldapMapper.entryToNode(entry)
} yield {
node
}
}

def getLDAPNodeInfo(nodeId: NodeId) : Box[LDAPNodeInfo] = {
logger.trace("Fetching node info for node id %s".format(nodeId.value))
for {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,9 @@ class AcceptFullInventoryInNodeOu(
, false
, false
, isPolicyServer
, DateTime.now // won't be used on save - dummy value
, ReportingConfiguration(None) // use global schedule
, Seq() //no user properties for now
)

val entry = ldapEntityMapper.nodeToEntry(node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ description: #54-Ubuntu SMP Thu Dec 10 17:23:29 UTC 2009
isSystem: false
isBroken: false
createTimestamp: 20070101000000Z
serializedNodeProperty: {"name":"foo", "value":"bar" }

dn: nodeId=node2,ou=Nodes,cn=rudder-configuration
objectClass: top
Expand Down Expand Up @@ -187,6 +188,7 @@ agentName: Nova
policyServerId:root-policy-server
ipHostNumber: 192.168.56.101
ipHostNumber: 127.0.0.1
environmentVariable: {"name":"SHELL","value":"/bin/sh"}

# Example of a node
dn: nodeId=node2,ou=Nodes,ou=Accepted Inventories,ou=Inventories,cn=rudder-configuration
Expand Down
Loading

0 comments on commit d8ee35b

Please sign in to comment.