Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

Use AST to pull a test's $Desired value #191

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 10 additions & 27 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,20 @@
# Contributing to Vester

Everyone is welcome to contribute to this project.
The goal is to add fine-grained tests that look at specific values within a vSphere environment, compare them to defined configuration value, and optionally remediate discrepancies if the user so decides.
However, there is nothing wrong with submitting a pull request (PR) with a non-remediating test.
This is a great starting point for those newer to coding with PowerShell!

## Contribution Requirements

Every test that is added to Vester needs three things:

1. An update to the example [`Config.ps1`][config] file with your required configuration value(s), comments, and accepted input type.
2. An update to the [`Config.Tests.ps1`][config.tests] file to validate that the `Config.ps1` file contains valid entries.
3. A test file using a properly formatted `Verb-Noun` format (use `Get-Verb` for more details) placed into the Tests folder.
Hello! We're always happy to hear from friends old and new. Here's some basic info about contributing for newcomers.

## Your First Contribution

If you're looking for your first bit of code to add, try this list:
If you're a first-timer, welcome! If you're not sure how to GitHub, allow me to humbly recommend a [GitHub 101] guide I wrote to try to help.

Fixing typos or updating outdated documentation is always welcome. New sets of eyes are a very scarce resource :slightly_smiling_face:

1. Identify a configuration value in your vSphere environment that isn't being inspected by Vester.
2. Use the [Template][template] to create a test that inspects this value and try it out locally.
3. At this point you can submit a pull request (PR) for a non-remediating test.
If someone else wants the remediation code added, they will grab your code and write that portion.
4. Optionally, write the remediation portion yourself to make a fully remediating test.
If you're submitting anything more substantial, we'd love if you would open an issue with your bug or feature request first, and then describe your pull request as resolving a single issue.

## Contribution Process
Vester is designed so that Someone Like You™ could [Write Your Own Vester Test]. If you have a small value in your vSphere environment you want to test for, we'd love to add more tests to the suite.

1. Create a fork of the project into your own repository.
2. From your fork, create a new feature branch (other than master) that expresses your feature or enhancement.
3. Make all your necessary changes in your feature branch.
4. Create a pull request with a description on what was added or removed and details explaining the changes in lines of code.
Questions? [Reach out!]

If approved, project owners will merge it.

[config]: https://github.com/WahlNetwork/Vester/blob/master/Configs/Config.ps1
[config.tests]: https://github.com/WahlNetwork/Vester/blob/master/Configs/Config.Tests.ps1
[template]: https://github.com/WahlNetwork/Vester/blob/master/Templates/Update-Template.ps1
[GitHub 101]: http://www.brianbunke.com/blog/2017/05/08/github-101/
[Write Your Own Vester Test]: http://www.brianbunke.com/blog/2017/03/09/write-your-own-vester-test/
[Reach out!]: /blob/master/README.md
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](http://semver.org/).



## [Unreleased]

### Added
- New Cluster HA tests ([#170][issue-170])
- HA-AdmissionControl-AutoComputePercentages
- HA-AdmissionControl-Resource-ReductionToToleratePercent
- HA-AdmissionControlEnabled
- HA-FailoverLevel
- HA-IsolationResponse
- HA-RestartPriority
- New Cluster VUM baseline attach test ([#175][issue-175]/[#179][issue-179])
- VUM-Attached-Baseline
- New vSAN tests, fresh from the VMworld US Hackathon!
- VSAN-DefaultHostDecommissionMode ([#173][issue-173])
- New Host test for vDS membership ([#176][issue-176])
- vDS-HostMembership

### Changed
- [#172][issue-172]
- `Get-VesterTest` now supports optional `$Recommendation` variables within Vester tests
- A use case for this is providing the "Security Config Guide" value for security tests
- `$Recommendation` added to VIB-AcceptanceLevel
- A new `Vester.Format.ps1xml` file more gracefully handles the custom `[Vester.Test]` objects that `Get-VesterTest` outputs
- Vester now requires `VMware.VumAutomation.Core` to support [#175][issue-175]
- Sort inventory objects when interactively using `New-VesterConfig` ([#186][issue-186])

### Fixed
- Support multiple datacenters by working around a PowerCLI bug ([#180][issue-180])
- `Invoke-Vester -XMLOutputFile -PassThru` no longer ignores `-PassThru` ([#189][issue-189])

### Welcome!
[@BrandonLundt](https://github.com/BrandonLundt) [@aaronwsmith](https://github.com/aaronwsmith) [@krobe](https://github.com/krobe) [@NamedJason](https://github.com/NamedJason) [@kanjibates](https://github.com/kanjibates)

### Much ❤
[@jeffgreenca](https://github.com/jeffgreenca) [@haberstrohr](https://github.com/haberstrohr)


## [1.2.0] - 2017-08-21
Dropped some long overdue documentation updates. New URL: https://wahlnetwork.github.io/Vester

Expand Down Expand Up @@ -127,3 +164,12 @@ Published just to reserve the name on the PowerShell Gallery. If you have this v
[issue-158]: https://github.com/WahlNetwork/Vester/issues/158
[issue-160]: https://github.com/WahlNetwork/Vester/issues/160
[issue-164]: https://github.com/WahlNetwork/Vester/issues/164
[issue-170]: https://github.com/WahlNetwork/Vester/issues/170
[issue-172]: https://github.com/WahlNetwork/Vester/issues/172
[issue-173]: https://github.com/WahlNetwork/Vester/issues/173
[issue-175]: https://github.com/WahlNetwork/Vester/issues/175
[issue-176]: https://github.com/WahlNetwork/Vester/issues/176
[issue-179]: https://github.com/WahlNetwork/Vester/issues/179
[issue-180]: https://github.com/WahlNetwork/Vester/issues/180
[issue-186]: https://github.com/WahlNetwork/Vester/issues/186
[issue-189]: https://github.com/WahlNetwork/Vester/issues/189
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@ Vester is a community project that provides an extremely light-weight approach t

Vester is written entirely in PowerShell, using [PowerCLI](https://www.vmware.com/support/developer/PowerCLI/) and [Pester](https://github.com/Pester/Pester). Config files are stored as json documents that can easily live in source control.

Please visit the **[full documentation](https://wahlnetwork.github.io/Vester)** for more details.
## Getting Started

This [three-part blog series](http://www.brianbunke.com/blog/2017/03/07/introducing-vester/) from March 2017 walks you through getting started with [Vester 1.0](https://www.powershellgallery.com/packages/Vester/1.0.1).
Vester 1.2 in ten minutes at VMworld US 2017: [vBrownBag video](https://youtu.be/9TRZ30XhK10)

Download Vester from the [PowerShell Gallery](https://www.powershellgallery.com/packages/Vester/).

```posh
Install-Module Vester
```

This [three-part blog series](http://www.brianbunke.com/blog/2017/03/07/introducing-vester/) from March 2017 walks you through getting started with v1.0. It still holds up; the main difference is the new `Get-VesterTest` function, making tests easier to fetch and explore.

## Documentation

You can find live docs online! https://wahlnetwork.github.io/Vester

Or in your PowerShell console:

```posh
Get-Command -Module Vester
Get-Help about_Vester
Get-Help Get-VesterTest -Full
```

**[Current changelog](https://github.com/WahlNetwork/Vester/blob/master/CHANGELOG.md)**

## Questions?

If you found a bug, would like to submit a feature request, or just have a question about Vester, feel free to search our [issues](https://github.com/WahlNetwork/Vester/issues) page, and create a new item if nothing fits the bill.

You're also welcome to come hang out in the #vester channel of the VMware {code} Slack workspace. [Sign up for VMware {code}](https://code.vmware.com/join), and you'll receive a Slack invite via email.
38 changes: 38 additions & 0 deletions Vester/Private/Get-VestConfigValue.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
function Get-VestConfigValue {
<#
.SYNOPSIS
Extract the $cfg.blah.blah value each Vester test uses.

.DESCRIPTION
Get-VestConfigValue uses the abstract syntax tree (AST) to parse the test
file, determine the $cfg value assigned to the $Desired variable within,
and output that $cfg value as a string for New-VesterConfig to consume.

.EXAMPLE
C:\DNS-Address.Vester.ps1 | Get-VestConfigValue
Returns the $cfg.blah.blah value assigned to the $Desired variable.

.NOTES
Consulted @ThmsRynr's AstHelper & @MathieuBuisson's PSCodeHealth modules. Thanks!
#>
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline = $true)]
$Vest
)

Write-Verbose "[Get-VestConfigValue] started for $(Split-Path $Vest -Leaf)"

$parse = [System.Management.Automation.Language.Parser]::ParseFile($Vest, [ref]$null, [ref]$null)

$ast = $parse.FindAll({$args[0] -is 'System.Management.Automation.Language.AssignmentStatementAst'}, $true)

$Output = $ast | Where-Object {
$_.Left.Extent.Text -eq '$Desired' -and
$_.Right.Extent.Text -like '$cfg.*'
}

Write-Debug "$($Output.Count) of $($ast.Count) objects will return. Inspect `$ast and `$Output for details"

Write-Output $Output.Right.Extent.Text
}
27 changes: 18 additions & 9 deletions Vester/Private/Set-VesterConfigValue.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,31 @@

function Set-VesterConfigValue {
[CmdletBinding()]
param ($Value)
param (
[ValidatePattern('^\$cfg\..*?\.')]
$Line,

$Value
)

# Using parent scope variables $config, $Matches, $Vest
$Split = $Line -split '\.'
$1 = $Split[1]
$2 = $Split[2]

If ($config.($Matches[1]).Keys -contains $Matches[2]) {
Write-Verbose "config.$($Matches[1]).$($Matches[2]) already exists; skipping $(Split-Path $Vest -Leaf)"
# Using parent scope variables $config, $Vest

If ($config.$1.Keys -contains $2) {
Write-Verbose "config.$1.$2 already exists; skipping $(Split-Path $Vest -Leaf)"
} Else {
# If config.host was already created in a previous ForEach loop,
If ($config.($Matches[1])) {
If ($config.$1) {
# Use the hashtable's Add method to append another value
$config.($Matches[1]).Add($Matches[2], $Value)
Write-Verbose "config.$($Matches[1]).$($Matches[2]) added"
$config.$1.Add($2, $Value)
Write-Verbose "config.$1.$2 added"
} Else {
# Otherwise, create the first value in the new scope
$config.($Matches[1]) = @{$Matches[2] = $Value}
Write-Verbose "config.$($Matches[1]).$($Matches[2]) added"
$config.$1 = @{$2 = $Value}
Write-Verbose "config.$1.$2 added"
}
}
}
58 changes: 4 additions & 54 deletions Vester/Public/New-VesterConfig.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -210,31 +210,17 @@ function New-VesterConfig {
Default {$null}
}

# TODO: Should probably offload this to a private function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see this happened. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I'm super happy with how this PR turned out, and how much freaking work I'll be doing with the AST moving forward...I think you found the easter egg I was most excited about. 👌

$CfgLine = (Select-String -Path $Vest.Full -Pattern '\$cfg') -replace '.*\:[0-9]+\:',''
$CfgLine -match '.*\$cfg\.([a-z]+)\.([a-z]+)$' | Out-Null
$CfgLine = Get-VestConfigValue -Vest $Vest.Full

# Run the $Actual script block, storing the result in $Result
If ($Object -and ($Result = & $Actual) -ne $null) {
# Call module private function Set-VesterConfigValue to add the entry
Set-VesterConfigValue -Value ($Result -as $Type)
Set-VesterConfigValue -Line $CfgLine -Value ($Result -as $Type)
} Else {
# Inventory $Object doesn't exist, or $Actual returned nothing
# Populate with null value; Invoke-Vester will skip this test
Set-VesterConfigValue -Value $null
Set-VesterConfigValue -Line $CfgLine -Value $null
} #if $Object and $Result

<# ### This works, but not currently used (see commented block below)
If ($config.$($Matches[1]).Keys -contains $($Matches[2]) -and -not $Quiet) {
# Record test/value correlation, if user wants to manually edit
$h = [PSCustomObject]@{
Full = $Vest.Full
Leaf = $Vest.Leaf
CfgValue = "$($Matches[1]).$($Matches[2])"
}
$TestHistory.Add($h)
}
#>
} #foreach $Vest

# If any values were populated in this scope, and the -Quiet flag is not active,
Expand All @@ -247,43 +233,7 @@ function New-VesterConfig {
$Sorted = $config.$Scope.GetEnumerator() | Sort-Object Name
$Sorted
$config.$Scope = [ordered]@{}
$Sorted | Foreach-Object { $config.$Scope.Add($_.Name, $_.Value) }

<# ###
# Users still need to manually edit the .json file if changes are desired
# The code block below works, but needs much more validation on entry
# For example, entering text into a "string[]" type does the following:
# The apostrophe, a common string wrapper, ends up in the json file as \u0027
# Not sure how to enter multiple string values (like muliple DNS servers)

If ((Read-HostColor 'Would you like to change any of these values? Y/N [N]') -like 'y*') {
Write-Host "`nIf there are any values you never want to test, enter " -NoNewline
Write-Host '$null' -ForegroundColor Red -NoNewline
Write-Host " to skip those tests.`n"
# TODO: ^ Entering $null still good instructions?

ForEach ($CfgLine in $config.$Scope.GetEnumerator() | Sort Name) {
$TestHistory | Where CfgValue -eq "$Scope.$($CfgLine.Name)" | ForEach-Object {
. $_.Full

Write-Host "$($_.Leaf) : $Title"
Write-Host $Description
Write-Host "[$Type]$($CfgLine.Name) = $($CfgLine.Value)"

If ((Read-HostColor 'Would you like to change this value? Y/N [N]') -like 'y*') {
$UserEnteredValue = Read-HostColor "Enter the new value of type '$Type'"
If ($UserEnteredValue -eq $null) {
$NewValue = $null
} Else {
$NewValue = $UserEnteredValue -as $Type
}
Write-Verbose "Setting $($Scope.ToLower()).$($CfgLine.Name) = $UserEnteredValue"
$config.$Scope.($CfgLine.Name) = $UserEnteredValue
} #if change single value
} #foreach $TestHistory
} #foreach $CfgLine
} #if change any value
#>
$Sorted | ForEach-Object { $config.$Scope.Add($_.Name, $_.Value) }

} #if $config.$Scope
} #foreach $Scope
Expand Down