Guest User

Untitled

a guest
Jul 16th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.84 KB | None | 0 0
  1. #<#
  2. #.Synopsis
  3. # Rewrite configuration files based on hiera data
  4. #.Description
  5. # ..
  6. #
  7. #.Parameter DataFile
  8. # Exported data from hiera (JSON)
  9. #.Parameter AppData
  10. # File to read configurable settings from
  11. #.Parameter DryRun
  12. # In dry run mode, we exit with status 100 to indicate changes needed but do not save the file
  13. #
  14. #.Example
  15. # # Reconfigure all files
  16. # configure_app
  17. #
  18. ##>
  19. param(
  20. [string] $DataFile = "C:\vagrant\mock.json",
  21. [string] $AppData = "C:\vagrant\appdata.txt",
  22. [switch] $DryRun = $false
  23. )
  24.  
  25. function ChildKeyFromXpath {
  26. param(
  27. [string] $XPath,
  28. [switch] $IgnoreMissing = $false
  29. )
  30. $childKeyCapture = [regex]::Match($xPath, '@[^=]+=''([^'']+?)'']/[^/]+$').captures.groups
  31. if ($childKeyCapture.length -ne 2) {
  32. if (-not $IgnoreMissing) {
  33. write-error "unable to find childKey in $($xPath) - xPath needs to map to an element in hiera eg //foo[@key='bar']/@value to lookup bar"
  34. exit 1
  35. }
  36. $childKey = $null
  37. } else {
  38. $childKey = $childKeyCapture[1]
  39. }
  40.  
  41. return $childKey
  42. }
  43.  
  44. function ReadXml {
  45. param(
  46. [string] $FilePath
  47. )
  48. # Read all the xml and do the edit at the requested xPath
  49. if(-not [System.IO.File]::Exists($FilePath)){
  50. write-error "File not found reading $($FilePath)"
  51. exit 1
  52. }
  53.  
  54. [xml] $xml = Get-Content($FilePath)
  55. if ($xml -eq $null -or $xml.ChildNodes.Count -eq 0 ) {
  56. write-error "Could not parse XML from $($FilePath) - invalid file content"
  57. exit 1
  58. }
  59.  
  60. return $xml
  61. }
  62.  
  63. # Ensure XML fragment exists at correct location
  64. function Ensure-XmlFragment {
  65. param(
  66. [string]$FilePath,
  67. [string]$XPath,
  68. [string]$ParentKey
  69. )
  70.  
  71. # remove the `ENSURE:` from the start of the XPath
  72. $XPath = $XPath -replace "ENSURE:", ""
  73.  
  74. $xml = ReadXml -FilePath $FilePath
  75.  
  76. # XPath should look like this:
  77. # //configuration/system.serviceModel/client/endpoint[@name='SystemEventsService']/identity
  78. # which means we need to get a reference to:
  79. # 1. //configuration/system.serviceModel/client/endpoint[@name='SystemEventsService']
  80. # 2. the child `identity`
  81. $captures = [regex]::Match($xPath, '^(.*?)/([^/]+)$').captures.groups
  82. $xPathBase = $captures[1]
  83. $targetElement = $captures[2]
  84.  
  85.  
  86. $nodes = (Select-Xml -Xml $xml -XPath $xPathBase)
  87. if ($nodes.node.count -eq 0) {
  88. write-error "XPath expression $($xPathBase) matches no nodes"
  89. exit 1
  90. }
  91. $childKey = ChildKeyFromXpath -xPath $XPath -IgnoreMissing
  92. $data = DataLookup -parentKey $ParentKey -childKey $childKey
  93.  
  94. $target = $nodes.node.$targetElement
  95. if ($target -eq $null) {
  96. # child (`identity` in above example) doesn't exist yet - create it
  97. $target = $xml.CreateElement($targetElement)
  98. $nodes.node.AppendChild($target) | Out-Null
  99. }
  100.  
  101. # update the xml string inside the target (`identity`) to reflect the data from hiera
  102. if ($target.InnerXml -ne $data) {
  103. $target.InnerXml = $data
  104.  
  105. if ($DryRun) {
  106. write-host "needs updating"
  107. exit 100
  108. } else {
  109. $xml.save($FilePath)
  110. }
  111. }
  112. }
  113.  
  114. # Set an XML attribute to a particular values
  115. function Set-AttributeValue {
  116. Param(
  117. [string]$FilePath,
  118. [string]$XPath,
  119. [string]$ParentKey
  120. )
  121. $xPathSplit = $XPath -split("/@")
  122. if ($xPathSplit.Length -ne 2) {
  123. write-error "xpath input is not correct - needs to capture an element, eg //foo[@key='bar']/@value but you sent '$($XPath)'"
  124. exit 1
  125. }
  126. $xPathBase = $xPathSplit[0]
  127. $xPathAttrib = $xPathSplit[1]
  128.  
  129. $childKey = ChildKeyFromXpath -xPath $xPath
  130.  
  131. # lookup the value to use for this config item
  132. $value = DataLookup -parentKey $parentKey -childKey $childKey
  133.  
  134. $xml = ReadXml -FilePath $FilePath
  135. $nodes = (Select-Xml -Xml $xml -XPath $xPathBase)
  136.  
  137. if ($nodes -eq $null) {
  138. # There must be a "slot" for us to insert values in the XMLs - we are not in the business
  139. # of creating parent nodes any more
  140. write-error "missing parent - create $($xPathBase) first and be aware of namespaces in xpath expressions"
  141. exit 1
  142. } else {
  143. if ($nodes.Node.Attributes[$xPathAttrib] -ne $null) {
  144. if ($nodes.Node.Attributes[$xPathAttrib].Value -eq $value) {
  145. $changesNeeded = $false
  146. } else {
  147. $nodes.Node.Attributes[$xPathAttrib].Value = $value
  148. $changesNeeded = $true
  149. }
  150. } else {
  151. $nodes.Node.SetAttribute($xPathAttrib,$value)
  152. $changesNeeded = $true
  153. }
  154.  
  155. if ($changesNeeded -and $DryRun) {
  156. write-host "Changes are required"
  157. exit 100
  158. }
  159. }
  160.  
  161. if (-not $DryRun) {
  162. $xml.Save($FilePath)
  163. }
  164. }
  165.  
  166.  
  167. #.Synopsys
  168. # Lookup data (from JSON file simulating hiera lookup)
  169. #.Parameter parentKey
  170. # The key to ask hiera for, eg `profile::foo::bar`
  171. #.Parameter childKey
  172. # Assuming the data returned from looking up `parentKey` is a hash, return the contents of this child element. If omitted,
  173. # Return all data looked up from parentKey
  174. function DataLookup {
  175. param(
  176. [String] $parentKey,
  177. [String] $childKey
  178. )
  179. $json = Get-Content $DataFile | ConvertFrom-Json
  180.  
  181. if ([string]::IsNullOrEmpty($childKey)) {
  182. $data = $json.$parentKey
  183. } else {
  184. $data = $json.$parentKey.$childKey
  185. }
  186.  
  187. if ($data -eq $null) {
  188. write-error "No data in hiera for '$($parentKey)' element '$($childKey)' - fix this!"
  189. exit 25
  190. }
  191.  
  192. return $data
  193. }
  194.  
  195.  
  196. $workingFile = $null
  197.  
  198. # appdata.txt is a simple textfile listing each app setting that must be managed
  199. # Format:
  200. # [c:\file\to\edit.xml]
  201. # XPATH==PARENT KEY IN HIERA
  202. # ENSURE:XPATH==PARENT KEY IN HIERA
  203. # Real example:
  204. # [C:\vagrant\web_config.xml]
  205. # //configuration/appSettings/add[@key='smtpHostName']/@value==boards::ipadserver::settings::appSettings
  206. # ENSURE://configuration/system.serviceModel/client/endpoint[@name='SystemEventsService']/identity==boards::ipadserver::spn
  207. #
  208. # The XPATH *must* take the form above, since this tells the script:
  209. # 1. How to find existing settings (attribute predicate: `key=SmtpHostName`, `name=SystemEventService`)
  210. # 2. Which attribute or element to write to (at the end of the XPATH: `/@value`, `/identity`)
  211. # 3. The element under the parent key to find the data in hiera (the value the predicate searches for: `smtpHostName`, `SystemEventService`)
  212. # 4. How to perform the update (line starts `ENSURE` we are adding a blob of xmltext otherwise we are setting an attribute)
  213. foreach($line in Get-Content $AppData) {
  214. # skip blank lines and comments
  215. $line = $line.trim()
  216. if ((-not ($line -match '^\s*[\n\r]*$')) -and (-not ($line -match '^\s*#'))) {
  217. if ($line.StartsWith('[')) {
  218. # Specify the current working file
  219. $workingFile = $line -replace "[][]", ""
  220. write-host "Working file set to $($workingFile)"
  221. } else {
  222. # must be something to lookup
  223. $lineSplit = $line -split('==')
  224. $xPath = $lineSplit[0]
  225. $parentKey = $lineSplit[1]
  226.  
  227. if ($lineSplit.Length -eq 2) {
  228. if ($workingFile -eq $null) {
  229. write-error "There is no working file! specify it in square brackets in appdata.txt before items to configure"
  230. exit 1
  231. }
  232.  
  233. if($line.StartsWith("ENSURE:")) {
  234. Ensure-XmlFragment -FilePath $workingFile -XPath $xPath -ParentKey $parentKey
  235. } else {
  236. Set-AttributeValue -FilePath $workingFile -XPath $xPath -ParentKey $parentKey
  237. }
  238. } else {
  239. write-error "item to lookup is not in correct format - should be XPATH==HIERA KEY but got: \n $($line)"
  240. exit 1
  241. }
  242. }
  243. }
  244. }
Add Comment
Please, Sign In to add comment