Git Product home page Git Product logo

psremotely's Introduction

Build status Documentation Status GitPitch

alt

PSRemotely, started as a fork of the Remotely project and over the time grew out of it. In a nutshell it let's you execute Pester tests against a remote machine. PSRemotely can use PoshSpec style infrastucture validation tests too.

Note - In the code & documentation the term 'Remotely' and 'PSRemotely' refer to the same.

It supports copying of the modules and artifacts to the remote node before the Pester tests are run.

Description

PSRemotely exposes a DSL which makes it easy to run Pester tests on the remote nodes. If you already have pester tests then you need to just wrap them inside the PSRemotely keyword and specify the node information using the Node keyword.

PSRemotely workflow is as under :

  1. Read PSRemotely.json file to determine the path & modules to be used on the remote nodes.
  2. Bootstrap the remote nodes, this involves
    • Testing the remote node path exists.
    • All the modules required are copied from the Lib/ folder to the remote node.
  3. Drop the Pester tests (Describe blocks) as individual tests file on the remote node. Also copy the items defined in the PSRemotely.json, which are placed under Artifacts/ folder inside local PSRemotely folder.
  4. Invoke the tests using background jobs on the remote nodes and wait for these jobs to complete, finally process and output a JSON object back.
  5. It also exports a global variable named $PSRemotely to which the Node bootstrap map and PSSession information is stored.

Remote Ops validation

Well this is a term coined by us for some of the infrastucture validation being done for Engineered solutions. So taking liberty to use this here.

Suppose, you already have below Pester test for some nodes in our environment:

Describe 'Bits Service test' {
    
    $BitsService = Get-Service -Name Bits
    
    It "Should have a service named bits" {
        $BitsService | Should Not BeNullOrEmpty
    }
    
    it 'Should be running' {
        $BitsService.Status | Should be 'Running'
    }
}

If you want to target the very same tests on the remote node named say AD,WDS & DHCP from your current workstation (part of the same domain), you can use PSRemotely.

Usage with PSRemotely:

PSRemotely {
	
    Node AD, WDS, DHCP {
		
        Describe 'Bits Service test' {
		
            $BitsService = Get-Service -Name Bits
            
            It "Should have a service named bits" {
                $BitsService | Should Not BeNullOrEmpty
            }
            
            It 'Should be running' {
                $BitsService.Status | Should be 'Running'
            }
        }		
	}
}

Once you have the tests file ready , save it with a .PSRemotely.ps1 extension, below is how you invoke the PSRemotely framework to start the remote ops validation :

Invoke-PSRemotely -Script <FileName>.PSRemotely.ps1

Output of the above is a JSON object, if the tests pass then an empty JSON object array of TestResult is returned otherwise the Error record thrown by Pester is returned :

{
    "Status":  true,
    "NodeName":  "WDS",
    "Tests":  [
                  {
                      "TestResult":  [

                                     ],
                      "Result":  true,
                      "Name":  "Bits Service test"
                  }
              ]
}
{
    "Status":  true,
    "NodeName":  "AD",
    "Tests":  [
                  {
                      "TestResult":  [

                                     ],
                      "Result":  true,
                      "Name":  "Bits Service test"
                  }
              ]
}
{
    "Status":  true,
    "NodeName":  "DHCP",
    "Tests":  [
                  {
                      "TestResult":  [

                                     ],
                      "Result":  true,
                      "Name":  "Bits Service test"
                  }
              ]
}

Initial PSRemotely setup

# One time setup
    # Download the repository
    # Unblock the zip
    # Extract the PSRemotely folder to a module path (e.g. $env:USERPROFILE\Documents\WindowsPowerShell\Modules\)

    #Simple alternative, if you have PowerShell 5, or the PowerShellGet module:
        Install-Module PSRemotely

# Import the module.
    Import-Module PSRemotely    # Alternatively, Import-Module \\Path\To\PSRemotely

# Get commands in the module
    Get-Command -Module PSRemotely

# Get help for the module and a command
    
    Get-Help Invoke-PSRemotely -full

More Information

The PSRemotely docs will include more information, including :

  • PSRemotely Basics
  • PSRemotely Examples
  • PSRemotely How Tos

Notes

Thanks goes to :

  • Remotely project
  • Ravikanth Chaganti - For all the help with the ideas and motivation behind the scenes.
  • Warren Frame's PSDeploy module - have been following Warren's module & documentation structure to organize.
  • [Pester module] (https://github.com/pester/pester), PSDesiredStateConfiguration module for borrowing some of the ideas.
  • PowerShell community & fellow MVPs, who are fantastic at helping each other.

TO DO

PSRemotely in its current form works for our needs to validate some of the Engineered solutions. But it has the potential to grow into something bigger, below are some of the items in the wishlist :

  • Use PowerShell classes, and add support for providers for nodes running either On-prem or on Cloud (AWS or Azure).
  • Integrate with JEA, since PSRemotely uses PSSession endpoints these can be locked down using JEA on the nodes.
  • More unit tests, lacking far behind in this aspect. More focus on it once we start working with the classes implementation.
  • Faster background processing of the remote node jobs, using runspaces.

Feel free to submit any ideas, bugs or pull requests.

psremotely's People

Contributors

adityapatwardhan avatar deepak-dhami avatar dexterposh avatar joeyaiello avatar rchaganti avatar stevel-msft avatar vors avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

psremotely's Issues

Add Integration tests

Add integration tests. For the most integration testing part, Remotely can be tested on the local machine, since it uses PS Remoting which we can be manipulated as per the requirement.

Invoke-PSRemotely mimic Invoke-Pester

Invoke-PSRemotely should do the following:

  • look for .PSRemotely.ps1 files in the current location (recursively) if nothing specified.
  • only accept .PSRemotely.ps1 files as input to the -ScriptFile parameter.

[Bug] ConfigData with Credential does not work

If you create a Example.PSRemotely.ps1 file with below content.

param($Credential)

# Configuration Data
$ConfigData = @{
	AllNodes = @(
		@{
			NodeName='*';
			DomainFQDN='dexter.lab';
            Credential = $Credential
		},
		@{
			NodeName="$env:ComputerName";
			ServiceName = 'bits';
			Type='Compute';

		},
		@{
			NodeName='localhost';
			ServiceName = 'winrm';
			Type='Storage';
		}
	)
}

# Remotely tests
Remotely -ConfigurationData $ConfigData {
	Node $AllNodes.Where({$PSItem.Type -eq 'Compute'}).NodeName {
		Describe 'Bits Service test' {
			
			$Service = Get-Service -Name $node.ServiceName # See the use of $node variable here
			
			It "Should have a service named bits" {
				$Service | Should Not BeNullOrEmpty
			}
			
			it 'Should be running' {
				$Service.Status | Should be 'Running'
			}
		}		
	}
}

This fails with the following error :
image

Reason -:
Within the Remotely function, we take config data and create the $ConfigData.AllNodes . Since each node is getting a credential object from the configuration data.

Now the logic is to pick up the credential object from the configuration data to start the PSSession, node properties (including Credential object) is being added as an argumentlist to the PSSessionOption.

Fix -:
Remove the Credential attribute from the node data.

Remove passing argument list while creating PSSession

Passing argument list to populate the Node variable in the PSRemoting session has limitations, as complex configuration data can not be passed. See below that passing nested arrays or hashes fails if we continue this way:

@{
	AllNodes = @(
		@{
			NodeName='*';
			DomainFQDN='dexter.lab';
			Networks = @( # nested array of hashes this can not be passed using application arguments
				@{
					Name = 'ConvergedNetwork1'
					VlanID = 101
				},
				@{
					Name = 'ConvergedNetwork2'
					VlanID = 102
				}
			)
		},
		@{
			NodeName="Node1";
			ServiceName = 'bits';
			Type='Compute';

		},
		@{
			NodeName='Node2';
			ServiceName = 'winrm';
			Type='Storage';
		}
	)
}

Use classes in PSRemotely - Support providers

Create a class which represents a PSRemotely node.
Now this will help us support different providers e.g. PSRemoting, Azure, AWS etc.
This provider will have a contract to return a SessionHashtable.

Now the class for the PSRemotely node will use this, agnostic of where the Node sits on.

Fix Start-RemotelyJobProcessing function logic.

In the v1.0.3 release, found out that the Start-RemotelyJobProcessing function started throwing below error. This indicates the flaw in logic where the Remotely job is being processed more than once.

PS C:\Users\Administrator\Desktop> $Error[3]
Add-Member : Cannot add a member with the name "__Streams" because a member with that name 
already exists. To overwrite the member anyway, add the Force parameter to your command.
At C:\Program Files\WindowsPowerShell\Modules\PSRemotely\1.0.3\Private\Helper.ps1:35 char:20
+ ... putStream = Add-Member -InputObject $outputStream -PassThru -MemberTy ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (@{TagFilter=Sys...et=S2D-Node-01}:PSObject) [ 
   Add-Member], InvalidOperationException
    + FullyQualifiedErrorId : MemberAlreadyExists,Microsoft.PowerShell.Commands.AddMemberComma 
   nd

Test script for Bootstrap.ps1

Is the Context block 'If all the required modules present on the Remotely node, and PSRemotely path is NOT present' required? Because, if the PSRemotely path is not present, modules also won't be present, as they resides inside that directory.

errors in README.md

The following code isn't working on my desktop.

Remotely {
    Node localhost {
        Describe 'Bits Service test' {

            $BitsService = Get-Service -Name Bits

            It "Should have a service named bits" {
                $BitsService | Should Not BeNullOrEmpty
            }

            it 'Should be running' {
                $BitsService.Status | Should be 'Running'
            }
        }       
    }
}

i've got an error asking me to fill some test parameter.

errors_psremotly

any idea ?

PSRemotely - Issue with parsing Describe blocks

While wrapping the Pester tests in PSRemotely, the test name needs to be at the first position mentioned like below :-

PSRemotely {
    Node AD {
        Describe 'testIPconfig' {
             # Tests here
        }
    }
}

At the moment for specifying tags, one has to use the below :-

PSRemotely {
    Node AD {
        Describe 'testIPconfig' -Tag DummyTag {
             # Tests here
        }
    }
}

If anything else then above is specified then parsing the Describe block for the test name fails. For example below fails :-

PSRemotely {
    Node AD {
        Describe -name 'testIPconfig'  {
             # Tests here
        }
    }
}

Below format also fails :-

PSRemotely {
    Node AD {
        Describe -Tag 'dummytag' 'testIPconfig' {
             # Tests here
        }
    }
}

Add a new debug function named Enter-PSRemotely

While trying to debug what ops validation test failed on the remote node, one usually has to reference the $PSRemotely.SessionHashtable.

Write a wrapper function, which should auto-complete the remote nodes names for the opened PSSession used by PSRemotely and drops into that remote PSSession.

Add check for invalid chars in the file names

PSRemotely dumps the .<Test_name>.tests.ps1 file on the remote node and also generates a Nunit style XML result file for the pester tests run.
As per the enhancement #48 , all the files will give preference to using NodeName for the tests and XML file.
But there is a gotcha with using NodeName here since the NodeName can have illegal filename characters in it.
Now, this bug uncovered in the integration tests for using IPv6, where the node name was '::1' and when dumping the files containing the nodename the error of an invalid character was thrown.

Integrate with JEA

Wishlist item :

  • Integrate the remote ops validation framework (PS Remotely) to use JEA endpoints.

Add Invoke-PSRemotely function in the Remote PSSession

As per #52 , a debug function to drop into underlying PSSession used for invoking pester will be created.
Inject a function named Invoke-PSRemotely in this underlying function which sort of takes care of invoking the ops validation on the remote node e.g. if the configuration data was passed then this should dynamically pass the $node as an argument to Pester etc.

ConfigurationData Connectivity via IP Address

When attempting to perform tests against computers that may be in a different Active Directory domain (isolated lab environment), then name resolution may not work from PSRemotely host machine. Ideally, I would like to be able to use the source configuration document used to deploy the lab, to be used by PSRemotely to run post deployment/operational tests.

Take the following configuration as an example:

# Configuration data
$ConfigData = @{
	AllNodes = @(
		@{
			NodeName='*';
			DomainFQDN='dexter.lab';
		},
		@{
			NodeName="Compute-11";
			ServiceName = 'vmms';
			Type='Compute';
			IPAddress = '192.168.1.2';
		},
		@{
			NodeName='Storage-12';
			ServiceName = 'bits';
			Type='Storage';
			IPAddress = '192.168.1.3';
		}
	)
}

# PSRemotely tests
PSRemotely -ConfigurationData $ConfigData {
	Node $AllNodes.Where({$PSItem.Type -eq 'Compute'}).NodeName {
		Describe 'Bits Service test' {
			
			$Service = Get-Service -Name $node.ServiceName # See the use of $node variable here
			
			It "Should have a service named bits" {
				$Service | Should Not BeNullOrEmpty
			}
			
			it 'Should be running' {
				$Service.Status | Should be 'Running'
			}
		}		
	}
}

I would like to be able to instruct PSRemotely to connect using the node's IPAddress node parameter, not the node name. In Lability there is a -PreferNodeProperty <string> parameter (not sure that's the best name) that instructs Lability to use the node's IPAddress property and not the node's name for connectivity.

Is this something that would be of benefit to add? if so, what needs to be done to implement it?!

Bootstrap nodes in parallel

At the moment, PSRemotely bootstrap nodes (makes them ready for ops validation) in sequential order.
Add the enhancement of bootstrapping them in parallel.

Error running on Server2008R2 Node

Hi,
running a simple test on a Server 2008R2 node produces following error:

VERBOSE: Helper.ps1 - Start-RemotelyJobProcessing - LineNo : 169 - PSRemotely job finished for Node ->
test03.xxx.de. Processing it now.
VERBOSE: Helper.ps1 - ProcessRemotelyOutputToJSON - LineNo : 170 - Cannot validate argument on parameter
'testResult'. The argument is null or empty. Provide an argument that is not null or empty, and then try the
command again.
VERBOSE: Invoke-PSRemotely.ps1 - Invoke-PSRemotely - LineNo : 202 - Error occurred in test script
'C:\PSRemotely Tests\Tests\Test.PSRemotely.ps1 -> at ProcessRemotelyOutputToJSON, C:\Program
Files\WindowsPowerShell\Modules\PSRemotely\1.0.3\Private\Helper.ps1: line 68

Running the same test against a Server 2012R2 node results in no errors.
Both have WMF updated to version 5.1.

[Discussion] Extensible bootstrap process

Extending the bootstrapping process should be easy. What I mean by that is you should be able to place a customstep.ps1 in say the bootstrap folder somewhere under PSRemotely. This customstep.ps1 should implement a Test-* and Set-* function which will be taken by PSRemotely and executed on the PSRemotely nodes during the bootstrapping.

Also surfacing this option in the PSRemotely.json would be a better idea.

Naming convention for tests file and the result

TODO - instead of the $env:computername , the node name defined in the environment config data should flow down for the *.Tests.ps1 file dumped on the remote node, Also the NunitXML report should use the node name.

This would be helpful when using report unit for the report creation.

[discussion] Skip the DSL

  • Scenario1 - Static hardcoded infra tests
    Try enabling a scenario where someone already has ops validation tests written e.g. WebServer.tests.ps1.
    These are hardcoded with the values inside the tests.
    PSRemotely should allow targeting the tests on the remote node using -Computername parameter?

  • Scenario2 - Using $Node inside the tests to abstract static data.
    Allow execution of the tests to be targeted to all the nodes specified in configuration data.
    While invoking tests on the nodes $Node will be passed inside the tests.

PreferNodeProperty - extend support to specify Credential

There are two ways to let PSRemotely know which credentials to use to connect to the remote node.

There is a downside to the second approach, it only looks for the attribute named credential (constraint on the name to be specific). Also if both credential hash and the credential attribute are present, the latter gets precedence.

Based on @iainbrighton's idea of using PreferNodeProperty, refer the issue for the idea -> #47.

Can we extend the same behavior for the credentials too? Would it make more sense this way? I think so.

Note - This would be a breaking change if anyone is using PSRemotely that way ๐Ÿ˜†.

Use Nuget repo or PSDeploy

On the machine from which Remotely is fired, look at setting up a Nuget repo.
This will help in resolving dependencies on the remotely nodes.

[Bug] Node block copies all artefacts

Node function just copies all the files placed in the artefacts folder at the moment.
It should actually only pick up files mentioned in the 'ArtefactsRequired' field of the Remotely.Json.

line 87 , Node.ps1

# copy/overwrite the artefacts on the remotely nodes
# TODO - Read the artefacts required from the $Remotely before copying them
Write-VerboseLog -Message "Copying artefacts on Node -> $nodeName"
Copy-Item -Path "$PSScriptRoot\..\Lib\Artefacts\*" -Destination "$($Remotely.RemotelyNodePath)\Lib\Artefacts" -Force -Recurse -ToSession $session 

PSRemotely maintain each node configuration

With the current implementation of PSRemotely, the required modules and required artefacts are assumed to be the same.

For Example - if a Manifest.xml is set to be one of the required artefacts then it gets copied to all the nodes.

Now this served our purpose well in a Remote ops validation of an Engineered solution but PSRemotely should have the ability to have Node specific or a group specific way of supplying these configurations.

This would get aligned well, when we start using classes.

PSRemotely support to pass tag or Pester Splat hash

This one is not completely ready. Want the ability to specify tags to PSRemotely while invoking it.

Invoke-PSRemotely -Script S2Dvalidation.PSRemotely.ps1 -Tag VMMReadiness

Now the above should flow down the tag to the remote nodes and only run ops validation tests marked with the same tag.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.