Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cmd/interlink/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/interlink-hq/interlink/pkg/interlink"
"github.com/interlink-hq/interlink/pkg/interlink/api"
ilpprof "github.com/interlink-hq/interlink/pkg/pprof"
"github.com/interlink-hq/interlink/pkg/virtualkubelet"
"k8s.io/cri-client/pkg/util"
)
Expand Down Expand Up @@ -112,6 +113,16 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

pprofAddr := interLinkConfig.Pprof.Address
if pprofAddr == "" {
pprofAddr = "127.0.0.1"
}
pprofPort := interLinkConfig.Pprof.Port
if pprofPort == "" {
pprofPort = "6061"
}
ilpprof.Start(ctx, interLinkConfig.Pprof.Enabled, pprofAddr+":"+pprofPort, "127.0.0.1:6061")

if os.Getenv("ENABLE_TRACING") == "1" {
shutdown, err := interlink.InitTracer(ctx, "InterLink-Plugin-")
if err != nil {
Expand Down
23 changes: 23 additions & 0 deletions cmd/ssh-tunnel/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"encoding/base64"
"flag"
"fmt"
Expand All @@ -9,6 +10,7 @@ import (
"net"
"os"

ilpprof "github.com/interlink-hq/interlink/pkg/pprof"
"golang.org/x/crypto/ssh"
)

Expand Down Expand Up @@ -63,8 +65,24 @@ func main() {
remotePort := flag.String("rport", "", "remote port for tunnel")
localSocket := flag.String("lsock", "", "local socket for tunnel")
hostkeyFile := flag.String("hostkeyfile", "", "file with public key for SSH host check")
pprofEnabled := flag.Bool("pprof", false, "enable pprof profiling")
pprofAddr := flag.String("pprof-address", "127.0.0.1", "pprof listen address")
pprofPort := flag.String("pprof-port", "6062", "pprof listen port")
flag.Parse()

enabled := *pprofEnabled
if os.Getenv("ENABLE_PPROF") == "true" {
enabled = true
}
pAddr := *pprofAddr
if os.Getenv("PPROF_ADDRESS") != "" {
pAddr = os.Getenv("PPROF_ADDRESS")
}
pPort := *pprofPort
if os.Getenv("PPROF_PORT") != "" {
pPort = os.Getenv("PPROF_PORT")
}

var hostKeyCallback ssh.HostKeyCallback

if *hostkeyFile == "" {
Expand Down Expand Up @@ -94,6 +112,11 @@ func main() {
if err != nil {
log.Fatalf("unable to parse private key: %v", err)
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ilpprof.Start(ctx, enabled, pAddr+":"+pPort, "127.0.0.1:6062")

// An SSH client is represented with a ClientConn.
//
// To authenticate with the remote server you must pass at least one
Expand Down
21 changes: 21 additions & 0 deletions cmd/virtual-kubelet/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import (
"k8s.io/client-go/informers"

"github.com/interlink-hq/interlink/pkg/interlink"
ilpprof "github.com/interlink-hq/interlink/pkg/pprof"
commonIL "github.com/interlink-hq/interlink/pkg/virtualkubelet"
)

Expand Down Expand Up @@ -464,6 +465,26 @@ func main() {
}

setupLogging(interLinkConfig)

pprofEnabled := vkConfig.Pprof.Enabled
if os.Getenv("ENABLE_PPROF") == "true" {
pprofEnabled = true
}
pprofAddr := vkConfig.Pprof.Address
if os.Getenv("PPROF_ADDRESS") != "" {
pprofAddr = os.Getenv("PPROF_ADDRESS")
}
if pprofAddr == "" {
pprofAddr = "127.0.0.1"
}
pprofPort := vkConfig.Pprof.Port
if os.Getenv("PPROF_PORT") != "" {
pprofPort = os.Getenv("PPROF_PORT")
}
if pprofPort == "" {
pprofPort = "6060"
}
ilpprof.Start(ctx, pprofEnabled, pprofAddr+":"+pprofPort, "127.0.0.1:6060")
log.G(ctx).Info("Config dump", interLinkConfig)

shutdownTracing := setupTracing(ctx)
Expand Down
24 changes: 24 additions & 0 deletions pkg/interlink/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ type Config struct {
DataRootFolder string `yaml:"DataRootFolder"`
// TLS contains TLS/mTLS configuration for secure communication
TLS TLSConfig `yaml:"TLS,omitempty"`
// Pprof contains configuration for the pprof profiling server
Pprof PprofConfig `yaml:"Pprof,omitempty"`
}

// PprofConfig holds configuration for the pprof profiling server.
type PprofConfig struct {
// Enabled indicates whether the pprof server is enabled
Enabled bool `yaml:"Enabled"`
// Address is the listen address for pprof server (default: 127.0.0.1)
Address string `yaml:"Address,omitempty"`
// Port is the listen port for pprof server (default: 6061)
Port string `yaml:"Port,omitempty"`
}

// TLSConfig holds TLS/mTLS configuration for secure communication.
Expand Down Expand Up @@ -373,5 +385,17 @@ func NewInterLinkConfig() (Config, error) {
interLinkNewConfig.Sidecarport = os.Getenv("SIDECARPORT")
}

if os.Getenv("ENABLE_PPROF") == "true" {
interLinkNewConfig.Pprof.Enabled = true
}

if os.Getenv("PPROF_PORT") != "" {
interLinkNewConfig.Pprof.Port = os.Getenv("PPROF_PORT")
}

if os.Getenv("PPROF_ADDRESS") != "" {
interLinkNewConfig.Pprof.Address = os.Getenv("PPROF_ADDRESS")
}

return interLinkNewConfig, nil
}
60 changes: 60 additions & 0 deletions pkg/pprof/pprof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package pprof

import (
"context"
"net"
"net/http"
_ "net/http/pprof" //nolint:gosec // G108: profiling endpoint exposure is intentional
"time"

"github.com/sirupsen/logrus"
)

// Start starts a pprof HTTP server in a background goroutine if enabled.
// It listens on listenAddr, falling back to defaultAddr if listenAddr is empty.
// The server stops when the provided context is canceled.
func Start(ctx context.Context, enabled bool, listenAddr string, defaultAddr string) {
if !enabled {
return
}

addr := listenAddr
if addr == "" {
addr = defaultAddr
}

if _, _, err := net.SplitHostPort(addr); err != nil {
isPortOnly := true
for _, r := range addr {
if r < '0' || r > '9' {
isPortOnly = false
break
}
}
if isPortOnly {
addr = ":" + addr
}
}

logrus.Infof("Starting pprof server on http://%s/debug/pprof/", addr)

server := &http.Server{
Addr: addr,
}

go func() {
<-ctx.Done()
logrus.Infof("Shutting down pprof server on %s", addr)
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
logrus.Errorf("pprof server on %s shutdown error: %v", addr, err)
}
}()

go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logrus.Errorf("pprof server on %s failed: %v", addr, err)
}
}()
}
65 changes: 65 additions & 0 deletions pkg/pprof/pprof_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package pprof

import (
"context"
"fmt"
"net"
"net/http"
"testing"
"time"
)

func freeAddr(t *testing.T) string {
t.Helper()
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to find a free port: %v", err)
}
addr := l.Addr().String()
l.Close()
return addr
}

func TestPprofStart(t *testing.T) {
addr := freeAddr(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Start(ctx, true, addr, "127.0.0.1:6060")

client := &http.Client{Timeout: 500 * time.Millisecond}
url := fmt.Sprintf("http://%s/debug/pprof/", addr)
var resp *http.Response
var err error
for i := 0; i < 10; i++ {
resp, err = client.Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
if err != nil {
t.Fatalf("pprof endpoint did not become ready: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200 OK, got %d", resp.StatusCode)
}
}

func TestPprofDisabled(t *testing.T) {
addr := freeAddr(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Start(ctx, false, addr, "127.0.0.1:6060")

conn, err := net.DialTimeout("tcp", addr, 200*time.Millisecond)
if err == nil {
_ = conn.Close()
t.Error("expected connection failure for disabled pprof server, but dial succeeded")
}
}
12 changes: 12 additions & 0 deletions pkg/virtualkubelet/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ type Config struct {
SkipDownwardAPIResolution bool `yaml:"SkipDownwardAPIResolution,omitempty"`
// DisableCSR disables CSR (CertificateSigningRequest) creation and uses self-signed certificates instead
DisableCSR bool `yaml:"DisableCSR,omitempty"`
// Pprof configures the pprof profiling server
Pprof PprofConfig `yaml:"Pprof,omitempty"`
}

// TLSConfig holds TLS/mTLS configuration for secure communication with interLink API.
Expand All @@ -72,6 +74,16 @@ type TLSConfig struct {
CACertFile string `yaml:"CACertFile,omitempty"`
}

// PprofConfig holds configuration for the pprof profiling server.
type PprofConfig struct {
// Enabled indicates whether the pprof server is enabled
Enabled bool `yaml:"Enabled"`
// Address is the listen address for pprof server (default: 127.0.0.1)
Address string `yaml:"Address,omitempty"`
// Port is the listen port for pprof server (default: 6060)
Port string `yaml:"Port,omitempty"`
}

// HTTP defines security settings for HTTP connections.
// It determines whether connections are insecure and holds CA certificates.
type HTTP struct {
Expand Down
Loading