diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e2c28d7..b2d0617 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -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 \ No newline at end of file +[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 diff --git a/CHANGELOG.md b/CHANGELOG.md index c8c1a4b..8837898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -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 diff --git a/README.md b/README.md index f42c4c1..0e30ebd 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/Vester/Private/Get-VestConfigValue.ps1 b/Vester/Private/Get-VestConfigValue.ps1 new file mode 100644 index 0000000..39eee78 --- /dev/null +++ b/Vester/Private/Get-VestConfigValue.ps1 @@ -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 +} diff --git a/Vester/Private/Set-VesterConfigValue.ps1 b/Vester/Private/Set-VesterConfigValue.ps1 index c7eefed..7bf49b9 100644 --- a/Vester/Private/Set-VesterConfigValue.ps1 +++ b/Vester/Private/Set-VesterConfigValue.ps1 @@ -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" } } } diff --git a/Vester/Public/New-VesterConfig.ps1 b/Vester/Public/New-VesterConfig.ps1 index fccbc7d..e3249bb 100644 --- a/Vester/Public/New-VesterConfig.ps1 +++ b/Vester/Public/New-VesterConfig.ps1 @@ -210,31 +210,17 @@ function New-VesterConfig { Default {$null} } - # TODO: Should probably offload this to a private function - $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, @@ -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