A simple package for allocating free ports adapted from Consul's freeport.
Like most Go packages, installing Porter is easy. First go get the package.
go get github.com/walkergriggs/porter
Next, import Porter.
import "github.com/walkergriggs/porter"
config := porter.DefaultConfig()
p, err := porter.New(config)
if err != nil {
panic(err)
}
defer p.Close()
ports := p.MustTake(5)
fmt.Println(ports)
// [10101 10102 10103 10104 10105]Porter takes three configuration variables: BlockSize, MaxBlocks, and LowerBound.
BlockSizeconfigures how many ports are alloted to a block.MaxBlocksconfigures how many blocks are considered.LowerBoundconfigures the lowest allocatable port.
Starting from the lower bound, Porter checks the range of each block, picks one at random, and takes out a lock on the first port. From that block, Porter filters a list of all available ports, which can reserved with Take and MustTake.
LowerBound = 8000
BlockSize = 100
MaxBlocks = 3
+-----------+-----------+-----------+
| Port Blocks (3) |
+-----------+-----------+-----------+
| 8000-8099 | 8100-8199 | 8200-8299 |
+-----------+-----------+-----------+
Before picking a block and locking the first port, we first adjust the MaxBlocks based on the host's ephemeral port range.
If any block overlaps with ephemeral ports, we trim MaxBlocks so the allocated blocks end just before the ephemeral ports.
LowerBound = 32600
BlockSize = 100
MaxBlocks = 3
+-----------------+-------------+-------------+
| Port Blocks (1) | Free | Ephemeral |
+-----------------+-------------+-------------+
| 32600-32699 | 32700-32767 | 32768-60999 |
+-----------------+-------------+-------------+