$hetznerCredentials = Get-Credential $nodeList = docker node ls --format '{{json .}}'| ConvertFrom-Json | ForEach-Object { docker node inspect $_.ID | ConvertFrom-Json } $onlineNodeList = $nodeList | Where-Object {$_.Spec.Availability -eq 'active'} if (!($nodeList | Where-Object {$_.Spec.Availability -ne 'active'})) { Write-Output 'all hosts online, nothing to failover' exit } $failoverAddressList = (Invoke-RestMethod -Uri 'https://robot-ws.your-server.de/failover' -Authentication Basic -Credential $hetznerCredentials).failover $onlineNodeAddressList = $onlineNodeList.Description.Hostname | ForEach-Object { dig +short $_ } $offlineAddressList = $failoverAddressList | Where-Object active_server_ip -notin $onlineNodeAddressList $maximumAddressCount = [Math]::Ceiling($failoverAddressList.Count / $onlineNodeList.Count) $i = 0 $addressGroupList = $onlineNodeAddressList | ForEach-Object { $nodeAddress = $_ @{ Count = [int]($addressGroupList | Where-Object {$_.Name -eq $nodeAddress}).Count NodeAddress = $nodeAddress } } | Sort-Object Count $distributionTarget = :distribution foreach ($addressGroup in $addressGroupList) { $currentAddressCount = $addressGroup.Count - 1 while ($currentAddressCount -lt $maximumAddressCount) { if (!$offlineAddressList[$i]) { # abort when all addresses are assigned break distribution } @{ active_server_ip = $addressGroup.NodeAddress ip = $offlineAddressList[$i++].ip node = (dig +short -x $($addressGroup.NodeAddress)) -replace '\.$' } $currentAddressCount++ } } # docker label updates must not run in parallel to prevent out-of-sequence errors $distributionTarget | ForEach-Object { # first add the new labels and afterwards remove the old ones # this prevents situations where no host has the label anymore $labelName = 'link.lubi.ip.'+$_.ip $filter = 'node.label='+$labelName $cleanupNodeList = docker node ls --filter $filter --format '{{json .}}' | ConvertFrom-Json $label = $labelName+'=true' docker node update --label-add $label $($_.node) $cleanupNodeList | ForEach-Object { docker node update --label-rm $labelName $($_.ID) } } $distributionTarget | ForEach-Object -ThrottleLimit $failoverAddressList.Count -Parallel { Invoke-RestMethod -Method Post -Uri ('https://robot-ws.your-server.de/failover/{0}' -f $_.ip) -Authentication Basic -Credential $using:hetznerCredentials -Body @{active_server_ip=$_.active_server_ip} }