Skip to content

Commit

Permalink
fix: make cni logs available via kubectl logs (#4845)
Browse files Browse the repository at this point in the history
* fix(cni): make cni logs available via kubectl logs

Signed-off-by: slonka <slonka@users.noreply.github.com>
  • Loading branch information
slonka authored Aug 17, 2022
1 parent 8b483ed commit ef89161
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 2 deletions.
38 changes: 37 additions & 1 deletion app/cni/pkg/cni/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"encoding/json"
"fmt"
"net"
"os"
"path"
"strconv"
"time"

"github.com/containernetworking/cni/pkg/skel"
Expand All @@ -24,10 +27,13 @@ import (
const (
podRetrievalMaxRetries = 30
podRetrievalInterval = 1 * time.Second
defaultLogLocation = "/tmp/kuma-cni.log"
defaultLogLevel = 2
defaultLogName = "kuma-cni"
)

var (
log = core.NewLoggerWithRotation(2, "/tmp/kuma-cni.log", 100, 0, 0).WithName("kuma-cni")
log = core.NewLoggerWithRotation(defaultLogLevel, defaultLogLocation, 100, 0, 0).WithName(defaultLogName)
)

// Kubernetes a K8s specific struct to hold config
Expand Down Expand Up @@ -85,13 +91,43 @@ func parseConfig(stdin []byte) (*PluginConf, error) {
return &conf, nil
}

func hijackMainProcessStderr() *os.File {
file, err := getCniProcessStderr()
if err != nil {
log.Error(err, "could not hijack main process file - continue logging to "+defaultLogLocation)
return nil
}
log.V(0).Info("successfully hijacked stderr of cni process - logs will be available in 'kubectl logs'")
os.Stderr = file
log = core.NewLoggerTo(os.Stderr, 2).WithName(defaultLogName)
return file
}

func getCniProcessStderr() (*os.File, error) {
pids, err := pidOf("/install-cni")
if err != nil {
return nil, err
}
if len(pids) != 1 {
return nil, errors.New("more than one process '/install-cni' running on a node, this should not happen")
}

file, err := os.OpenFile(path.Join("/", "proc", strconv.Itoa(pids[0]), "fd", "2"), os.O_WRONLY, 0)
return file, err
}

// cmdAdd is called for ADD requests
func cmdAdd(args *skel.CmdArgs) error {
ctx := context.Background()
conf, err := parseConfig(args.StdinData)
if err != nil {
return errors.Wrap(err, "error parsing kuma-cni cmdAdd config")
}

mainProcessStderr := hijackMainProcessStderr()
if mainProcessStderr != nil {
defer mainProcessStderr.Close()
}
logPrevResult(conf)

// Determine if running under k8s by checking the CNI args
Expand Down
84 changes: 84 additions & 0 deletions app/cni/pkg/cni/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package cni

import (
"bytes"
"errors"
"io"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"unicode"
)

// PidOf Find process(es) with a specified name (string match)
// copied from https://github.com/kubernetes/kubernetes/blob/v1.24.3/pkg/util/procfs/procfs_linux.go#L99
// with small modifications
// and return their pid(s)
func pidOf(name string) ([]int, error) {
if len(name) == 0 {
return []int{}, errors.New("name should not be empty")
}
return getPids(name), nil
}

// we don't need regex so this is changed to "string"
func getPids(name string) []int {
pids := []int{}

dirFD, err := os.Open("/proc")
if err != nil {
return nil
}
defer dirFD.Close()

for {
// Read a small number at a time in case there are many entries, we don't want to
// allocate a lot here.
ls, err := dirFD.Readdir(10)
if err == io.EOF {
break
}
if err != nil {
return nil
}

for _, entry := range ls {
if !entry.IsDir() {
continue
}

// If the directory is not a number (i.e. not a PID), skip it
pid, err := strconv.Atoi(entry.Name())
if err != nil {
continue
}

cmdline, err := ioutil.ReadFile(filepath.Join("/proc", entry.Name(), "cmdline"))
if err != nil {
continue
}

// The bytes we read have '\0' as a separator for the command line
parts := bytes.SplitN(cmdline, []byte{0}, 2)
if len(parts) == 0 {
continue
}
// Split the command line itself we are interested in just the first part
exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool {
return unicode.IsSpace(c) || c == ':'
})
if len(exe) == 0 {
continue
}
// Check if the name of the executable is what we are looking for
if name == exe[0] {
// Grab the PID from the directory path
pids = append(pids, pid)
}
}
}

return pids
}
2 changes: 1 addition & 1 deletion app/cni/pkg/install/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (
)

var (
log = core.NewLoggerWithRotation(2, "/tmp/install-cni.log", 100, 0, 0).WithName("install-cni")
log = core.NewLoggerTo(os.Stderr, 2).WithName("install-cni")
)

func removeBinFiles() error {
Expand Down
1 change: 1 addition & 0 deletions pkg/core/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var (
// TODO remove dependency on kubernetes see: https://github.com/kumahq/kuma/issues/2798
Log = kube_log.Log
NewLogger = kuma_log.NewLogger
NewLoggerTo = kuma_log.NewLoggerTo
NewLoggerWithRotation = kuma_log.NewLoggerWithRotation
SetLogger = kube_log.SetLogger
Now = time.Now
Expand Down

0 comments on commit ef89161

Please sign in to comment.