69 lines
1.5 KiB
Go
69 lines
1.5 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright Authors of K9s
|
|
|
|
package port
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"net"
|
|
|
|
"github.com/derailed/k9s/internal/slogs"
|
|
)
|
|
|
|
// PortTunnels represents a collection of tunnels.
|
|
type PortTunnels []PortTunnel
|
|
|
|
// CheckAvailable checks if all port tunnels are available.
|
|
func (t PortTunnels) CheckAvailable(ctx context.Context) error {
|
|
for _, pt := range t {
|
|
if !IsPortFree(ctx, pt) {
|
|
return fmt.Errorf("port %s is not available on host", pt.LocalPort)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// PortTunnel represents a host tunnel port mapper.
|
|
type PortTunnel struct {
|
|
Address, Container, LocalPort, ContainerPort string
|
|
}
|
|
|
|
// NewPortTunnel returns a new instance.
|
|
func NewPortTunnel(a, co, lp, cp string) PortTunnel {
|
|
return PortTunnel{
|
|
Address: a,
|
|
Container: co,
|
|
LocalPort: lp,
|
|
ContainerPort: cp,
|
|
}
|
|
}
|
|
|
|
// String dumps as string.
|
|
func (t PortTunnel) String() string {
|
|
return fmt.Sprintf("%s|%s|%s:%s", t.Address, t.Container, t.LocalPort, t.ContainerPort)
|
|
}
|
|
|
|
// PortMap returns a port mapping.
|
|
func (t PortTunnel) PortMap() string {
|
|
if t.LocalPort == "" {
|
|
t.LocalPort = t.ContainerPort
|
|
}
|
|
|
|
return t.LocalPort + ":" + t.ContainerPort
|
|
}
|
|
|
|
// IsPortFree checks if a address/port pair is available on host.
|
|
func IsPortFree(ctx context.Context, t PortTunnel) bool {
|
|
var ncfg net.ListenConfig
|
|
s, err := ncfg.Listen(ctx, "tcp", fmt.Sprintf("%s:%s", t.Address, t.LocalPort))
|
|
if err != nil {
|
|
slog.Warn("Port is not available", slogs.Port, t.LocalPort, slogs.Address, t.Address)
|
|
return false
|
|
}
|
|
|
|
return s.Close() == nil
|
|
}
|