Revision 3f50c558
Added by François ARMAND about 6 years ago
inventory-fusion/src/main/scala/com/normation/inventory/provisioning/fusion/FusionReportParsingExtension.scala | ||
---|---|---|
|
||
package com.normation.inventory.provisioning.fusion
|
||
|
||
import scala.xml.{Node,NodeSeq}
|
||
import scala.xml.Node
|
||
import com.normation.inventory.domain.InventoryReport
|
||
|
||
/**
|
||
... | ... | |
*/
|
||
abstract class FusionReportParsingExtension extends PartialFunction[(Node,InventoryReport) , InventoryReport] {
|
||
|
||
}
|
||
}
|
inventory-fusion/src/main/scala/com/normation/inventory/provisioning/fusion/FusionReportUnmarshaller.scala | ||
---|---|---|
package fusion
|
||
|
||
import com.normation.inventory.domain._
|
||
import com.normation.inventory.provisioning.fusion._
|
||
import java.io.InputStream
|
||
import org.joda.time.DateTime
|
||
import org.joda.time.format.DateTimeFormat
|
||
import java.util.Locale
|
||
import com.normation.utils.StringUuidGenerator
|
||
import com.normation.utils.Utils._
|
||
import java.net.InetAddress
|
||
import scala.xml._
|
||
import org.xml.sax.SAXParseException
|
||
import net.liftweb.common._
|
||
import com.normation.inventory.domain.InventoryConstants._
|
||
import com.normation.inventory.services.provisioning._
|
||
import org.joda.time.format.DateTimeFormatter
|
||
import com.normation.utils.Control.sequence
|
||
import com.normation.inventory.domain.NodeTimezone
|
||
|
||
class FusionReportUnmarshaller(
|
||
... | ... | |
|
||
//same as above, but handle conversion to int
|
||
private[this] def optInt (n:NodeSeq, tag: String): Option[Int] = convert(optText(n \ tag), tag, "Int" , java.lang.Integer.parseInt)
|
||
private[this] def optLong (n:NodeSeq, tag: String): Option[Long] = convert(optText(n \ tag), tag, "Long" , java.lang.Long.parseLong)
|
||
private[this] def optFloat (n:NodeSeq, tag: String): Option[Float] = convert(optText(n \ tag), tag, "Float" , java.lang.Float.parseFloat)
|
||
private[this] def optDouble(n:NodeSeq, tag: String): Option[Double] = convert(optText(n \ tag), tag, "Double", java.lang.Double.parseDouble)
|
||
|
||
... | ... | |
)
|
||
}
|
||
|
||
/**
|
||
/*
|
||
* Insert bios, manufacturer and system serial in the inventory
|
||
* If Manufacturer or System Serial Number is already defined, skip them and write
|
||
* a warn log
|
||
... | ... | |
report.copy(node = report.node.copy(networks = nets))
|
||
}
|
||
|
||
/*
|
||
* Try to normalize ARCH. We want to provide to the user something common: i686, x86_64, ppc64, etc.
|
||
* We are going to use https://stackoverflow.com/questions/15036909/clang-how-to-list-supported-target-architectures
|
||
* as reference names.
|
||
* Fusion provides // we change to:
|
||
* - amd64 => x86_64
|
||
* - if OS == AIX => ppc64
|
||
* - PowerPC => ppc (AIX already taken care of, and AFAIK we don't have any mean to be more precise, even with CPU info)
|
||
* - PowerPC (other cases) => ppc
|
||
* - 32-bit / 64-bit (windows) => x86 / x86_64
|
||
* - things with x86_64 / x86 / i*86 in their name => x86_64 / x86 / i*86
|
||
* - IA-64, i[3-9]86, x86, x86_64, arm.*, other => identical [lower case]
|
||
*/
|
||
private[this] def normalizeArch(os: OsDetails)(s: String): String = {
|
||
val ix86 = """.*(i[3-9]86).*""".r
|
||
val x86 = """.*(x86|32-bit).*""".r
|
||
val x86_64 = """.*(x86_64|amd64|64-bit).*""".r
|
||
val aix = """.*(aix).*""".r
|
||
|
||
if(os.os == AixOS) {
|
||
"ppc64"
|
||
} else {
|
||
s.toLowerCase() match {
|
||
case "powerpc" => "ppc"
|
||
// x64_64 must be check before x86 regex
|
||
case x86_64(_) => "x86_64"
|
||
case x86(_) => "x86"
|
||
case ix86(x) => x
|
||
case aix(_) => "ppc64"
|
||
case x => x
|
||
}
|
||
}
|
||
}
|
||
|
||
// ******************************************** //
|
||
// parsing implementation details for each tags //
|
||
// ******************************************** //
|
||
... | ... | |
*
|
||
* *** Operating System infos ***
|
||
* ARCHNAME : architecture type.
|
||
* Ex: "x86_64-linux-gnu-thread-multi"
|
||
* We want i686, x86_64, armv7l, etc
|
||
* VMSYSTEM : The virtualization technologie used if the machine is a virtual machine.
|
||
* Can be: Physical (default), Xen, VirtualBox, Virtual Machine, VMware, QEMU, SolarisZone, Aix LPAR, Hyper-V
|
||
*
|
||
... | ... | |
, name = optText(xml\\"NAME")
|
||
, ram = optText(xml\\"MEMORY").map(m => MemorySize(m + ramUnit))
|
||
, swap = optText(xml\\"SWAP").map(m=> MemorySize(m + swapUnit))
|
||
, archDescription = optText(xml\\"ARCHNAME")
|
||
// update arch ONLY if it is not yet defined
|
||
, archDescription = report.node.archDescription.orElse(optText(xml\\"ARCHNAME").map(normalizeArch(report.node.main.osDetails)))
|
||
, lastLoggedUser = optText(xml\\"LASTLOGGEDUSER")
|
||
, lastLoggedUserTime = try {
|
||
optText(xml\\"DATELASTLOGGEDUSER").map(date => userLoginDateTimeFormat.parseDateTime(date) )
|
||
... | ... | |
|
||
def processOsDetails(xml:NodeSeq, report:InventoryReport, contentNode:NodeSeq) : InventoryReport = {
|
||
/*
|
||
* ARCH : operating system arch (i686, x86_64...)
|
||
*
|
||
* FULL_NAME : full os description string
|
||
* SUSE Linux Enterprise Server 11 (x86_64)
|
||
* KERNEL_NAME : the type of OS
|
||
... | ... | |
case _ => None
|
||
}
|
||
|
||
report.copy( node = report.node.copyWithMain(m => m.copy (osDetails = osDetail) ).copy(timezone = timezone) )
|
||
// for arch, we want to keep the value only in the case where OPERATINGSYSTEM/ARCH is missing
|
||
val arch = optText(xml\\"ARCH").map(normalizeArch(report.node.main.osDetails)).orElse(report.node.archDescription)
|
||
|
||
report.copy( node = report.node.copyWithMain(m => m.copy (osDetails = osDetail) ).copy(timezone = timezone, archDescription = arch ) )
|
||
|
||
}
|
||
|
inventory-fusion/src/main/scala/com/normation/inventory/provisioning/fusion/PostUnmarshallCheckConsistency.scala | ||
---|---|---|
package com.normation.inventory.provisioning
|
||
package fusion
|
||
|
||
import com.normation.inventory.domain.InventoryReport
|
||
import net.liftweb.common._
|
||
import scala.xml.NodeSeq
|
||
import com.normation.utils.Control.{pipeline, bestEffort}
|
||
import com.normation.utils.Control.pipeline
|
||
import com.normation.inventory.services.provisioning._
|
||
import scala.xml.Elem
|
||
|
inventory-fusion/src/test/scala/com/normation/inventory/provisioning/fusion/TestReportParsing.scala | ||
---|---|---|
import org.specs2.runner._
|
||
import com.normation.utils.StringUuidGeneratorImpl
|
||
import net.liftweb.common._
|
||
import scala.xml.XML
|
||
import java.io.File
|
||
import com.normation.inventory.domain._
|
||
|
||
... | ... | |
|
||
private[this] implicit class TestParser(parser: FusionReportUnmarshaller) {
|
||
def parse(reportRelativePath: String): InventoryReport = {
|
||
import java.net.URL
|
||
val url = this.getClass.getClassLoader.getResource(reportRelativePath)
|
||
if(null == url) throw new NullPointerException(s"Resource with relative path '${reportRelativePath}' is null (missing resource? Spelling? Permissions?)")
|
||
val is = url.openStream()
|
||
... | ... | |
"correctly parse the timezone" in {
|
||
report.node.timezone must beEqualTo(Some(NodeTimezone("CEST", "+0200")))
|
||
}
|
||
|
||
}
|
||
|
||
"Arch in Inventory" should {
|
||
|
||
"be defined for windows 2012" in {
|
||
val arch = parser.parse("fusion-report/WIN-AI8CLNPLOV5-2014-06-20-18-15-49.ocs").node.archDescription
|
||
arch must beEqualTo(Some("x86_64"))
|
||
}
|
||
|
||
"correctly get the arch when OPERATINGSYSTEM/ARCH is defined" in {
|
||
val arch = parser.parse("fusion-report/signed_inventory.ocs").node.archDescription
|
||
arch must beEqualTo(Some("x86_64"))
|
||
}
|
||
|
||
"correctly get the arch even if OPERATINGSYSTEM/ARCH is missing" in {
|
||
val arch = parser.parse("fusion-report/sles-10-64-sp3-2011-08-23-16-06-17.ocs").node.archDescription
|
||
arch must beEqualTo(Some("x86_64"))
|
||
}
|
||
|
||
"be 'ppc64' on AIX" in {
|
||
val arch = parser.parse("fusion-report/sovma136-2014-02-10-07-13-43.ocs").node.archDescription
|
||
arch must beEqualTo(Some("ppc64"))
|
||
}
|
||
}
|
||
|
||
"Agent in Inventory" should {
|
||
|
||
"should be empty when there is no agent" in {
|
||
"be empty when there is no agent" in {
|
||
val agents = parser.parse("fusion-report/rudder-tag/minimal-zero-agent.ocs").node.agents.map(_.name).toList
|
||
agents must be empty
|
||
}
|
||
|
||
"should have one agent when using community" in {
|
||
"have one agent when using community" in {
|
||
val agents = parser.parse("fusion-report/rudder-tag/minimal-one-agent.ocs").node.agents.map(_.name).toList
|
||
agents == (COMMUNITY_AGENT :: Nil)
|
||
}
|
||
|
||
"should have two agent when using community and nova" in {
|
||
"have two agent when using community and nova" in {
|
||
val agents = parser.parse("fusion-report/rudder-tag/minimal-two-agents.ocs").node.agents.map(_.name).toList
|
||
agents == (COMMUNITY_AGENT :: NOVA_AGENT :: Nil)
|
||
}
|
||
|
||
"should be empty when there is two agents, using two different policy servers" in {
|
||
"be empty when there is two agents, using two different policy servers" in {
|
||
val agents = parser.parse("fusion-report/rudder-tag/minimal-two-agents-fails.ocs").node.agents.map(_.name).toList
|
||
agents must be empty
|
||
}
|
Also available in: Unified diff
Fixes #11918: Incorrect detection of architecture on Ubuntu 14.04 32 bits