Runway.Yaml.psm1
<#
Code in this file will be added to the beginning of the .psm1. For example, you should place any using statements here. #> Function Get-RwJobYaml { [cmdletbinding( DefaultParameterSetName = 'ById' )] param ( [Parameter( Mandatory, ParameterSetName = 'ById' )] [Parameter( Mandatory, ParameterSetName = 'ById-Id' )] [Parameter( Mandatory, ParameterSetName = 'ById-Name' )] [string[]]$JobId, [Parameter( Mandatory, ParameterSetName = 'ByName' )] [Parameter( Mandatory, ParameterSetName = 'ByName-Id' )] [Parameter( Mandatory, ParameterSetName = 'ByName-Name' )] [string[]]$JobName, [Parameter( Mandatory, ParameterSetName = 'ByName-Id' )] [Parameter( Mandatory, ParameterSetName = 'ById-Id' )] [switch]$IncludeAssignedRunnersById, [Parameter( Mandatory, ParameterSetName = 'ByName-Name' )] [Parameter( Mandatory, ParameterSetName = 'ById-Name' )] [switch]$IncludeAssignedRunnersByName ) $jobs = if ($PSCmdlet.ParameterSetName -like 'ByName*') { foreach ($name in $jobName) { Get-RwJobByName -JobName $name } } elseif ($PSCmdlet.ParameterSetName -like 'ById*') { foreach ($id in $JobId) { Get-RwJob -JobId $id } } # Build basic job $jobHt = @{} $jobHt['jobs'] = @{} foreach ($job in $jobs ) { $jobHt['jobs'][$job.Name] = [ordered]@{ tags = @($job.Tags) schedule = [ordered]@{ type = $job.Schedule.ScheduleType weekdays = $job.Schedule.Weekdays time = $job.Schedule.Time repeatMinutes = $job.Schedule.RepeatMinutes } runners = @{ tags = @( 'setme' ) } actions = foreach ($action in (Sort-RwJobActions -Actions $job.Actions)) { [ordered]@{ name = $action.ActionName parameters = & { $ht = @{} foreach ($param in $action.Settings) { $ht[$param.Name] = $param.Value } $ht } connector = @{ id = $action.ConnectionId } } } } switch ($PSCmdlet.ParameterSetName) { { ($_ -like 'ByName*') } { $job = Get-RwJob -JobId $job.Id } { ($_ -like '*-Id') } { $jobHt['jobs'][$job.Name]['runners'] = @{ Ids = (Get-RwSetMember -SetId $job.EndpointSetId).Id } } { ($_ -like '*-Name') } { $jobHt['jobs'][$job.Name]['runners'] = @{ Names = (Get-RwSetMember -SetId $job.EndpointSetId).Name } } } } # Clean up null connectors and parameters $connectorCache = @{} foreach ($job in $jobHt['jobs'].Keys) { foreach ($action in $jobHt['jobs'][$job]['actions']) { if ($null -eq $action['connector']['id']) { $action.Remove('connector') } else { if ($connectorCache.Keys -notcontains $action['connector']['id']) { $connectorCache[$action['connector']['id']] = Get-RwConnection -ConnectionId $action['connector']['id'] } $action['connector']['name'] = $connectorCache[$action['connector']['id']].Name $action['connector'].Remove('id') } $toRemove = foreach ($key in $action.parameters.Keys) { if ($null -eq $action.parameters[$key]) { $key } } foreach ($key in $toRemove) { $action.parameters.Remove($key) } if ($action.parameters.Count -eq 0) { $action.Remove('parameters') } } } if ($connectorCache.Keys.Count -gt 0) { $jobHt['connectors'] = foreach ($connector in $connectorCache.Keys) { $conn = Get-RwConnection -ConnectionId $connector [ordered]@{ $conn.Name = [ordered]@{ action = @{ name = $conn.ActionName } runner = @{ name = $conn.AssignedEndpointName } parameters = & { $ht = @{} foreach ($param in $conn.Settings) { $ht[$param.Name] = $param.Value } $ht } } } } } $jobHt | ConvertTo-Yaml } Function Get-RwResourceFromCache { [cmdletbinding()] param ( [Parameter( Mandatory )] [ValidateSet('Action','Runner')] [string]$ResourceType, [Parameter( Mandatory )] [string]$Name ) if ($null -eq (Get-Variable -Scope Script -Name 'rwCache' -ErrorAction SilentlyContinue)) { $rwCache = @{} $rwCache['Action'] = @{} $rwCache['Runner'] = @{} } if ($rwCache[$ResourceType].Keys -notcontains $Name) { $rwCache[$ResourceType][$Name] = switch ($ResourceType) { 'Action' { Get-RwRepository -Name $Name } 'Runner' { Get-RwRunnerByName -AssetName $Name } } } $rwCache[$ResourceType][$Name] } Function New-RwJobSchedule { [cmdletbinding()] param ( [int]$RepeatMinutes, [string]$Time, [string]$Type, [string]$WeekDays ) $scheduleSplat = @{ repeatMinutes = $RepeatMinutes Time = $Time scheduletype = if ($PSBoundParameters.Keys -contains 'Type') { $Type } else { 'RunNow' } weekdays = $WeekDays } New-RwJobScheduleObject @scheduleSplat } Function Sort-RwJobActions { [cmdletbinding()] param ( [RunwaySdk.PowerShell.Models.ActionInstance[]]$Actions ) $ht = @{} foreach ($action in $Actions) { $ht[$action.Id] = $action } for ($x = 0; $x -lt $Actions.Count; $x++) { if ($x -eq 0) { Tee-Object -InputObject ($Actions | Where-Object { $null -eq $_.PrevActionId }) -Variable prev } else { if ($prev.NextActionId) { Tee-Object -InputObject ($ht[$prev.NextActionId]) -Variable prev } } } } Function Sync-RwResourceYaml { [cmdletbinding( DefaultParameterSetName = 'FromString' )] param ( [Parameter( ParameterSetName = 'FromString' )] [string]$Yaml, [Parameter( ParameterSetName = 'FromFile' )] [string]$PathToYaml, [switch]$Test ) if ($PSCmdlet.ParameterSetName -eq 'FromFile') { $Yaml = Get-Content -Raw $PathToYaml } $currentUser = Get-RwAuthenticationCurrentUser Write-Verbose "Context:`n- Name: $($currentUser.name)`n- Email: $($currentUser.emailAddress)`n- Home Group: $($currentUser.homeContainerId)" $resources = ConvertFrom-Yaml $yaml # If there are any connectors if ($resources.connectors) { Write-Information "Found $($resources.connectors.count) connectors" Write-Information "Connectors:" foreach ($connector in $resources.connectors.Keys) { Write-Information "- $connector" # Leveraging a cache for the Action names if ($resources.connectors[$connector].Keys -contains 'action') { if ($resources.connectors[$connector]['action'] -contains 'id') { $actionId = $resources.connectors[$connector]['action']['id'] } else { $actionId = (Get-RwResourceFromCache -ResourceType Action -Name $resources.connectors[$connector]['action']['name']).Id } } # Leveraging a cache for the Runner names if ($resources.connectors[$connector].Keys -contains 'runner') { if ($resources.connectors[$connector]['runner'] -contains 'id') { $runnerId = $resources.connectors[$connector]['runner']['id'] } else { $runnerId = (Get-RwResourceFromCache -ResourceType Runner -Name $resources.connectors[$connector]['runner']['name']).Id } } $splat = @{ Name = $connector ActionId = $actionId RunnerId = $runnerId IsHidden = $false GroupId = $currentUser.HomeContainerId } if ($resources.connectors[$connector].Keys -contains 'parameters') { $splat['settings'] = $resources.connectors[$connector]['parameters'] } $conn = Get-RwConnectionByName $connector if ($null -ne $conn) { Write-Information ' - Updating existing Connector' if ($Test.IsPresent) { Write-Information " - Would update existing Connector" } else { Set-RwConnection @splat -ConnectionId $conn.Id -ErrorAction Stop } } else { Write-Information ' - Creating new connector' if ($Test.IsPresent) { Write-Information " - Would create new Connector" } else { New-RwConnection @splat } } # Assign Tags if ($resources.connectors[$connector].Keys -contains 'tags') { if ($Test.IsPresent) { Write-Information " - Would add tags: $($resources.connectors[$connector]['tags'] -join ',')" } else { # Build a set $set = New-RwSet # Add the job to the set if ($null -eq $conn) { $conn = Get-RwConnectionByName -ConnectionName $connector } Add-RwSetToSet -TargetSetId $set -ObjectIds $conn.Id # Add the tags to the set Write-Information " - Adding tags: $($resources.connectors[$connector]['tags'] -join ',')" Add-RwTag -SetId $set -Tags $resources.connectors[$connector]['tags'] } } } } else { Write-Information "No connectors found." } # If there are any jobs if ($resources.jobs) { Write-Information "Found $($resources.jobs.count) jobs" Write-Information 'Jobs:' foreach ($job in $resources.jobs.Keys) { Write-Information "- $job" # Create job if it doesn't already exist $existingJob = Get-RwJobByName $job if ($null -ne $existingJob) { Write-Verbose ' - Updating existing' $existingJob = Get-RwJob -JobId $existingJob.Id } else { Write-Verbose ' - Creating a new one' if ($Test.IsPresent) { Write-Information " - Would create job" } else { $newJob = New-RwJob -Name $job -IsEnabled -IsHidden:$false $existingJob = Get-RwJob -JobId $newJob.JobId } } # Assign Schedule if ($resources.jobs[$job].Keys -contains 'schedule') { Write-Information " - Adding Schedule" # Create the schedule object $sched = $resources.jobs[$job]['schedule'] $schedule = New-RwJobSchedule @sched # Set the schedule if ($Test.IsPresent) { Write-Information " - Would set schedule to $($scheduleSplat | ConvertTo-Json -Compress)" } else { Set-RwJobSchedule -JobId $existingJob.Id -Schedule $schedule } } # Assign Actions if ($resources.jobs[$job].Keys -contains 'actions') { Write-Information ' - Adding Actions' $x = 0 $actions = foreach ($action in $resources.jobs[$job]['actions']) { $x++ $actionHt = @{} if ($action.Keys -contains 'id') { $actionHt['RepositoryActionId'] = $action['id'] } else { $actionHt['RepositoryActionId'] = (Get-RwResourceFromCache -ResourceType Action -Name $action['name']).Id } Write-Information " - $x`: '$($action['name'])'" Write-Verbose "Associating '$($action['name'])' to '$($actionHt['RepositoryActionId'])'" if ($action.Keys -contains 'parameters') { Write-Information " - Adding parameters" $actionHt['Settings'] = $action['parameters'] } if ($action.Keys -contains 'connector') { Write-Information " - Adding connector" if ($action['connector'].Keys -contains 'id') { $actionHt['ConnectionId'] = $action['connector']['id'] } elseif ($action['connector'].Keys -contains 'name') { $actionHt['ConnectionId'] = (Get-RwConnectionByName -ConnectionName $action['connector']['name']).Id } } $actionHt } if ($Test.IsPresent) { Write-Information " - Would Update Actions" } else { Set-RwJobAction -JobId $existingJob.Id -Request $actions } } # Assign Runners if ($resources.jobs[$job].Keys -contains 'runners') { Write-Information ' - Adding Runners' $newMembers = if ($resources.jobs[$job]['runners'].Keys -contains 'names') { Write-Information " - Adding runners by name" (Get-RwRunnerByName -AssetName $resources.jobs[$job]['runners']['names']).AssetId } elseif ($resources.jobs[$job]['runners'].Keys -contains 'tags') { Write-Information " - Adding Runners by tags: '$($resources.jobs[$job]['runners']['tags'] -join "','")'." (Get-RwEndpointByTag -Tags $resources.jobs[$job]['runners']['tags']).Id } Write-Information " - Found $($newMembers.Count) total Runners that should be assigned" if ($Test.IsPresent) { Write-Information " - Would update membership" } else { Sync-RwSetMembership -Members $newMembers -SetId $existingJob.EndpointSetId } } # Assign Tags if ($resources.jobs[$job].Keys -contains 'tags') { if ($Test.IsPresent) { Write-Information " - Would add tags: $($resources.jobs[$job]['tags'] -join ',')" } else { # Build a set $set = New-RwSet # Add the job to the set Add-RwSetToSet -TargetSetId $set -ObjectIds $existingJob.Id # Add the tags to the set Write-Information " - Adding tags: $($resources.jobs[$job]['tags'] -join ',')" Add-RwTag -SetId $set -Tags $resources.jobs[$job]['tags'] } } } } else { Write-Information "No jobs found." } } Function Sync-RwSetMembership { [CmdletBinding()] param ( [string[]]$Members, [string]$SetId ) $existingMembers = Get-RwSetMember -SetId $SetId Write-Verbose "Current set membership count: $($existingMembers.Count)" # Finding any existing members that don't meet the filter $toRemove = [System.Collections.Generic.List[string]]::new() $toAdd = [System.Collections.Generic.List[string]]::new() foreach ($existingMember in $existingMembers.Items) { if ($newMembers.Items.Id -notcontains $existingMember.Id) { #Write-Verbose "Will remove $($existingMember.Id)" $toRemove.Add($existingMember.Id) } } # Find any matching members that need to be added foreach ($newMember in $Members) { if ($existingMembers.Items.Id -notcontains $newMember) { #Write-Verbose "Will add $($newMember)" $toAdd.Add($newMember) } } # Remove unneeded runners if ($toRemove.Count -gt 0) { Write-Verbose "Removing $($toRemove.Count) Runners from the set" Remove-RwSetFromSet -TargetSetId $SetId -ObjectIds $toRemove | Out-Null } # Add those runners to the job set if ($toAdd.Count -gt 0) { Write-Verbose "Adding $($toRemove.Count) Runners to the set" Add-RwSetToSet -TargetSetId $SetId -ObjectIds $toAdd | Out-Null } } <# Code in this file will be added to the end of the .psm1. For example, you should set variables or other environment settings here. #> |