From 29e7e03bbb6e4a9789d402f89bf954e28b6803d6 Mon Sep 17 00:00:00 2001 From: Atul-source Date: Wed, 4 Sep 2024 19:11:38 +0530 Subject: [PATCH] addressed comments Signed-off-by: Atul-source --- .github/workflows/codeql.yaml | 36 +----- apis/handlers/addprog.go | 2 +- apis/handlers/deleteprog.go | 2 +- apis/handlers/restart_linux.go | 62 ++++------ apis/handlers/updateconfig.go | 2 +- artifact/artifact.go | 206 --------------------------------- bpfprogs/bpf.go | 178 +++++++++++++++++++++++++++- bpfprogs/bpf_test.go | 3 +- bpfprogs/bpfdebug.go | 5 +- bpfprogs/nfconfig.go | 14 ++- config/config.go | 14 ++- config/l3afd.cfg | 9 +- main.go | 90 +++++++++----- models/l3afd.go | 17 ++- restart/restart.go | 59 ++++------ stats/metrics.go | 5 +- 16 files changed, 326 insertions(+), 378 deletions(-) delete mode 100644 artifact/artifact.go diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 5a467011..cc1fe7d5 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -26,7 +26,7 @@ jobs: actions: read contents: read security-events: write - + strategy: fail-fast: false matrix: @@ -39,40 +39,12 @@ jobs: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Checkout repository - uses: actions/checkout@2d7d9f7ff5b310f983d059b68785b3c74d8b8edd + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - name: Initialize CodeQL - uses: github/codeql-action/init@e1f83c153a6cb7134f035e16e2626b216e7168c9 + uses: github/codeql-action/init@4dd16135b69a43b6c8efb853346f8437d92d3c93 with: languages: ${{ matrix.language }} - - name: Autobuild - uses: github/codeql-action/autobuild@9e39a05578dd315aad814d3c71bd03472cc5b815 - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4067cdab784c667cf1b7fa95169f3a0e0a381d63 - with: - category: "/language:${{matrix.language}}" - output: sarif-results - upload: failure-only - - - name: filter-sarif - uses: advanced-security/filter-sarif@59d0a64b3c0a34d787819f6659708915b6210582 - with: - patterns: | - +**/*.go - -artifact/artifact.go - input: sarif-results/go.sarif - output: sarif-results/go.sarif - - - name: Upload SARIF - uses: github/codeql-action/upload-sarif@2bbafcdd7fbf96243689e764c2f15d9735164f33 - with: - sarif_file: sarif-results/go.sarif - - - name: Upload loc as a Build Artifact - uses: actions/upload-artifact@b18b1d32f3f31abcdc29dee3f2484801fe7822f4 - with: - name: sarif-results - path: sarif-results - retention-days: 1 + uses: github/codeql-action/analyze@4dd16135b69a43b6c8efb853346f8437d92d3c93 \ No newline at end of file diff --git a/apis/handlers/addprog.go b/apis/handlers/addprog.go index 3e40e5ca..1c3d37d8 100644 --- a/apis/handlers/addprog.go +++ b/apis/handlers/addprog.go @@ -42,7 +42,7 @@ func AddEbpfPrograms(ctx context.Context, bpfcfg *bpfprogs.NFConfigs) http.Handl }(&mesg, &statusCode) if models.IsReadOnly { log.Warn().Msgf("We are in Between Restart Please try after some time") - mesg = "We are in Between Restart Please try after some time" + mesg = "We are currently in the middle of a restart. Please attempt again after a while." return } defer DecWriteReq() diff --git a/apis/handlers/deleteprog.go b/apis/handlers/deleteprog.go index fe0ed052..43614e75 100644 --- a/apis/handlers/deleteprog.go +++ b/apis/handlers/deleteprog.go @@ -42,7 +42,7 @@ func DeleteEbpfPrograms(ctx context.Context, bpfcfg *bpfprogs.NFConfigs) http.Ha }(&mesg, &statusCode) if models.IsReadOnly { log.Warn().Msgf("We are in Between Restart Please try after some time") - mesg = "We are in Between Restart Please try after some time" + mesg = "We are currently in the middle of a restart. Please attempt again after a while." return } defer DecWriteReq() diff --git a/apis/handlers/restart_linux.go b/apis/handlers/restart_linux.go index 5df78da1..e7e2f9d1 100644 --- a/apis/handlers/restart_linux.go +++ b/apis/handlers/restart_linux.go @@ -11,14 +11,13 @@ import ( "net" "os" "os/exec" - "regexp" + "path/filepath" "strconv" "strings" "syscall" "time" "net/http" - "net/url" "github.com/rs/zerolog/log" @@ -50,7 +49,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { }(&mesg, &statusCode) if models.IsReadOnly { log.Warn().Msgf("We are in Between Restart Please try after some time") - mesg = "We are in Between Restart Please try after some time" + mesg = "We are currently in the middle of a restart. Please attempt again after a while." statusCode = http.StatusInternalServerError return } @@ -73,14 +72,6 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { statusCode = http.StatusInternalServerError return } - - match, _ := regexp.MatchString(`^v\d+\.\d+\.\d+$`, t.Version) - if !match { - mesg = "version naming convention is wrong it will like vx.y.z" - log.Error().Msg(mesg) - statusCode = http.StatusInternalServerError - return - } machineHostname, err := os.Hostname() if err != nil { mesg = "failed to get os hostname" @@ -94,25 +85,6 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { statusCode = http.StatusInternalServerError return } - URL, err := url.Parse(t.ArtifactURL) - if err != nil { - mesg = "url format is wrong" - log.Error().Msg(mesg) - statusCode = http.StatusInternalServerError - return - } - if URL.Scheme != models.HttpScheme && URL.Scheme != models.FileScheme && URL.Scheme != models.HttpsScheme { - mesg = "currently only http,https,file is supported" - log.Error().Msg(mesg) - statusCode = http.StatusInternalServerError - return - } - if strings.Contains(t.ArtifactURL, "..") { - mesg = "bad string" - log.Error().Msg(mesg) - statusCode = http.StatusInternalServerError - return - } defer func() { models.IsReadOnly = false }() @@ -128,14 +100,14 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { time.Sleep(time.Millisecond) } - oldCfgPath, err := restart.ReadSymlink(bpfcfg.HostConfig.BasePath + "/latest/l3afd.cfg") + oldCfgPath, err := restart.ReadSymlink(filepath.Join(bpfcfg.HostConfig.BasePath, "latest/l3afd.cfg")) if err != nil { mesg = fmt.Sprintf("failed read symlink: %v", err) log.Error().Msg(mesg) statusCode = http.StatusInternalServerError return } - oldBinPath, err := restart.ReadSymlink(bpfcfg.HostConfig.BasePath + "/latest/l3afd") + oldBinPath, err := restart.ReadSymlink(filepath.Join(bpfcfg.HostConfig.BasePath, "latest/l3afd")) if err != nil { mesg = fmt.Sprintf("failed to read symlink: %v", err) log.Error().Msg(mesg) @@ -144,12 +116,18 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { } oldVersion := strings.Split(strings.Trim(oldBinPath, bpfcfg.HostConfig.BasePath+"/"), "/")[0] - err = restart.GetNewVersion(t.ArtifactURL, oldVersion, t.Version, bpfcfg.HostConfig) + if _, ok := models.AvailableVersions[t.Version]; !ok { + mesg = "invalid version to upgrade" + log.Error().Msg(mesg) + statusCode = http.StatusInternalServerError + return + } + err = restart.GetNewVersion(models.L3AFDRestartArtifactName, oldVersion, models.AvailableVersions[t.Version], bpfcfg.HostConfig) if err != nil { - mesg = fmt.Sprintf("failed to getNewVersion: %v", err) + mesg = fmt.Sprintf("failed to get new version: %v", err) log.Error().Msg(mesg) statusCode = http.StatusInternalServerError - err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig) + err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, models.AvailableVersions[t.Version], bpfcfg.HostConfig) mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err) return } @@ -158,7 +136,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { ln, err := net.Listen("unix", models.HostSock) if err != nil { log.Err(err) - err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig) + err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, models.AvailableVersions[t.Version], bpfcfg.HostConfig) mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err) statusCode = http.StatusInternalServerError return @@ -195,7 +173,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { lf, err := lis.File() if err != nil { log.Error().Msgf("%v", err) - err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig) + err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, models.AvailableVersions[t.Version], bpfcfg.HostConfig) mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err) statusCode = http.StatusInternalServerError isErr = true @@ -209,7 +187,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { return } // we have added - cmd := exec.Command(bpfcfg.HostConfig.BasePath+"/latest/l3afd", "--config", bpfcfg.HostConfig.BasePath+"/latest/l3afd.cfg") + cmd := exec.Command(filepath.Join(bpfcfg.HostConfig.BasePath, "latest/l3afd"), "--config", filepath.Join(bpfcfg.HostConfig.BasePath, "latest/l3afd.cfg")) cmd.SysProcAttr = &syscall.SysProcAttr{ Setsid: true, } @@ -238,7 +216,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { log.Error().Msgf("%v", err) mesg = mesg + fmt.Sprintf("unable to create pid file: %v", err) } - err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig) + err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, models.AvailableVersions[t.Version], bpfcfg.HostConfig) if err != nil { mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err) } @@ -257,7 +235,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { f = true break } - fmt.Println("Waiting for socket to be up...") + log.Info().Msgf("Waiting for socket to be up...") time.Sleep(time.Second) // sleep for a second before trying again } if !f { @@ -296,7 +274,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { log.Error().Msgf("%v", err) mesg = mesg + fmt.Sprintf("unable to create pid file: %v", err) } - err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig) + err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, models.AvailableVersions[t.Version], bpfcfg.HostConfig) if err != nil { mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err) } @@ -327,7 +305,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc { log.Error().Msgf("%v", err) mesg = mesg + fmt.Sprintf("unable to create pid file: %v", err) } - err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig) + err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, models.AvailableVersions[t.Version], bpfcfg.HostConfig) if err != nil { mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err) } diff --git a/apis/handlers/updateconfig.go b/apis/handlers/updateconfig.go index c0d5152c..b6f7e16f 100644 --- a/apis/handlers/updateconfig.go +++ b/apis/handlers/updateconfig.go @@ -42,7 +42,7 @@ func UpdateConfig(ctx context.Context, bpfcfg *bpfprogs.NFConfigs) http.HandlerF }(&mesg, &statusCode) if models.IsReadOnly { log.Warn().Msgf("We are in Between Restart Please try after some time") - mesg = "We are in Between Restart Please try after some time" + mesg = "We are currently in the middle of a restart. Please attempt again after a while." return } defer DecWriteReq() diff --git a/artifact/artifact.go b/artifact/artifact.go deleted file mode 100644 index c0e31c5c..00000000 --- a/artifact/artifact.go +++ /dev/null @@ -1,206 +0,0 @@ -package artifact - -import ( - "archive/tar" - "archive/zip" - "bytes" - "compress/gzip" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/l3af-project/l3afd/v2/models" -) - -var ( - copyBufPool sync.Pool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }} -) - -func DownloadArtifact(urlpath string, timeout time.Duration, buf *bytes.Buffer) error { - URL, err := ValidateURL(urlpath) - if err != nil { - return err - } - switch URL.Scheme { - case models.HttpScheme, models.HttpsScheme: - { - timeOut := time.Duration(timeout) * time.Second - var netTransport = &http.Transport{ - ResponseHeaderTimeout: timeOut, - } - client := http.Client{Transport: netTransport, Timeout: timeOut} - // Get the data - resp, err := client.Get(URL.String()) - if err != nil { - return fmt.Errorf("download failed: %w", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("get request returned unexpected status code: %d (%s), %d was expected\n\tResponse Body: %s", resp.StatusCode, http.StatusText(resp.StatusCode), http.StatusOK, buf.Bytes()) - } - buf.ReadFrom(resp.Body) - return nil - } - case models.FileScheme: - { - if FileExists(URL.Path) { - f, err := os.Open(URL.Path) - if err != nil { - return fmt.Errorf("opening err : %w", err) - } - buf.ReadFrom(f) - f.Close() - } else { - return fmt.Errorf("artifact is not found") - } - return nil - } - default: - return fmt.Errorf("unknown url scheme") - } -} -func ExtractArtifact(artifactName string, buf *bytes.Buffer, tempDir string) error { - switch artifact := artifactName; { - case strings.HasSuffix(artifact, ".zip"): - { - c := bytes.NewReader(buf.Bytes()) - zipReader, err := zip.NewReader(c, int64(c.Len())) - if err != nil { - return fmt.Errorf("failed to create zip reader: %w", err) - } - for _, file := range zipReader.File { - - zippedFile, err := file.Open() - if err != nil { - return fmt.Errorf("unzip failed: %w", err) - } - defer zippedFile.Close() - - extractedFilePath, err := ValidatePath(file.Name, tempDir) - if err != nil { - return err - } - - if file.FileInfo().IsDir() { - os.MkdirAll(extractedFilePath, file.Mode()) - } else { - outputFile, err := os.OpenFile( - extractedFilePath, - os.O_WRONLY|os.O_CREATE|os.O_TRUNC, - file.Mode(), - ) - if err != nil { - return fmt.Errorf("unzip failed to create file: %w", err) - } - defer outputFile.Close() - - buf := copyBufPool.Get().(*bytes.Buffer) - _, err = io.CopyBuffer(outputFile, zippedFile, buf.Bytes()) - if err != nil { - return fmt.Errorf("GetArtifacts failed to copy files: %w", err) - } - copyBufPool.Put(buf) - } - } - return nil - } - case strings.HasSuffix(artifact, ".tar.gz"): - { - archive, err := gzip.NewReader(buf) - if err != nil { - return fmt.Errorf("failed to create Gzip reader: %w", err) - } - defer archive.Close() - tarReader := tar.NewReader(archive) - - for { - header, err := tarReader.Next() - - if err == io.EOF { - break - } else if err != nil { - return fmt.Errorf("untar failed: %w", err) - } - - fPath, err := ValidatePath(header.Name, tempDir) - if err != nil { - return err - } - - info := header.FileInfo() - if info.IsDir() { - if err = os.MkdirAll(fPath, info.Mode()); err != nil { - return fmt.Errorf("untar failed to create directories: %w", err) - } - continue - } - - file, err := os.OpenFile(fPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) - if err != nil { - return fmt.Errorf("untar failed to create file: %w", err) - } - defer file.Close() - - buf := copyBufPool.Get().(*bytes.Buffer) - _, err = io.CopyBuffer(file, tarReader, buf.Bytes()) - if err != nil { - return fmt.Errorf("GetArtifacts failed to copy files: %w", err) - } - copyBufPool.Put(buf) - } - return nil - } - default: - return fmt.Errorf("unknown artifact format") - } -} - -func ValidateURL(urlpath string) (*url.URL, error) { - URL, err := url.Parse(urlpath) - if err != nil { - return nil, fmt.Errorf("unknown url format : %w", err) - } - if URL.Scheme == "" { - return nil, fmt.Errorf("URL scheme is missing") - } - if URL.Scheme == models.HttpScheme || URL.Scheme == models.HttpsScheme { - if URL.Host == "" { - return nil, fmt.Errorf("URL host is missing") - } - // Forbid fragment in the URL to prevent potential attacks - if URL.Fragment != "" { - return nil, fmt.Errorf("URL must not contain a fragment") - } - } - if strings.Contains(URL.Path, "..") { - return nil, fmt.Errorf("URL path must not contain '..'") - } - return URL, nil -} - -func ValidatePath(filePath string, destination string) (string, error) { - destpath := filepath.Join(destination, filePath) - if strings.Contains(filePath, "..") { - return "", fmt.Errorf(" file contains filepath (%s) that includes (..)", filePath) - } - if !strings.HasPrefix(destpath, filepath.Clean(destination)+string(os.PathSeparator)) { - return "", fmt.Errorf("%s: illegal file path", filePath) - } - return destpath, nil -} - -// fileExists checks if a file exists or not -func FileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} diff --git a/bpfprogs/bpf.go b/bpfprogs/bpf.go index 119ed532..d5b399ff 100644 --- a/bpfprogs/bpf.go +++ b/bpfprogs/bpf.go @@ -5,12 +5,17 @@ package bpfprogs import ( + "archive/tar" + "archive/zip" "bytes" + "compress/gzip" "container/ring" "context" "errors" "fmt" + "io" "net" + "net/http" "net/url" "os" "os/exec" @@ -18,10 +23,10 @@ import ( "path/filepath" "strconv" "strings" + "sync" "time" "unsafe" - "github.com/l3af-project/l3afd/v2/artifact" "github.com/l3af-project/l3afd/v2/config" "github.com/l3af-project/l3afd/v2/models" "github.com/l3af-project/l3afd/v2/stats" @@ -34,7 +39,8 @@ import ( ) var ( - execCommand = exec.Command + execCommand = exec.Command + copyBufPool sync.Pool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }} ) //lint:ignore U1000 avoid false linter error on windows, since this variable is only used in linux code @@ -165,7 +171,7 @@ func LoadRootProgram(ifaceName string, direction string, progType string, conf * // On l3afd crashing scenario verify root program are unloaded properly by checking existence of persisted maps // if map file exists then root program didn't clean up pinned map files - if artifact.FileExists(rootProgBPF.MapNamePath) { + if fileExists(rootProgBPF.MapNamePath) { log.Warn().Msgf("previous instance of root program %s persisted map %s file exists", rootProgBPF.Program.Name, rootProgBPF.MapNamePath) if err := rootProgBPF.RemoveRootProgMapFile(ifaceName); err != nil { log.Warn().Err(err).Msgf("previous instance of root program %s map file not removed successfully - %s ", rootProgBPF.Program.Name, rootProgBPF.MapNamePath) @@ -620,12 +626,12 @@ func (b *BPF) GetArtifacts(conf *config.Config) error { urlpath := path.Join(RepoURL, b.Program.Name, b.Program.Version, platform, b.Program.Artifact) log.Info().Msgf("Retrieving artifact - %s", urlpath) - err = artifact.DownloadArtifact(urlpath, conf.HttpClientTimeout, buf) + err = DownloadArtifact(urlpath, conf.HttpClientTimeout, buf) if err != nil { return err } tempDir := filepath.Join(conf.BPFDir, b.Program.Name, b.Program.Version) - err = artifact.ExtractArtifact(b.Program.Artifact, buf, tempDir) + err = ExtractArtifact(b.Program.Artifact, buf, tempDir) if err != nil { return fmt.Errorf("unable to extract artifact %w", err) } @@ -651,6 +657,15 @@ func (b *BPF) createUpdateRulesFile(direction string) (string, error) { } +// fileExists checks if a file exists or not +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + // Add eBPF map into BPFMaps list func (b *BPF) AddBPFMap(mapName string) error { bpfMap, err := b.GetBPFMap(mapName) @@ -1380,7 +1395,7 @@ func (b *BPF) PinBpfMaps(ifaceName string) error { mapFilename = filepath.Join(b.HostConfig.BpfMapDefaultPath, ifaceName, k) } // In case one of the program pins the map then other program will skip - if !artifact.FileExists(mapFilename) { + if !fileExists(mapFilename) { if err := v.Pin(mapFilename); err != nil { return fmt.Errorf("eBPF program %s map %s:failed to pin the map err - %w", b.Program.Name, mapFilename, err) } @@ -1497,3 +1512,154 @@ func (b *BPF) StopUserProgram(ifaceName, direction string) error { } return nil } + +func DownloadArtifact(urlpath string, timeout time.Duration, buf *bytes.Buffer) error { + URL, err := url.Parse(urlpath) + if err != nil { + return fmt.Errorf("unknown url format : %w", err) + } + switch URL.Scheme { + case models.HttpScheme, models.HttpsScheme: + { + timeOut := time.Duration(timeout) * time.Second + var netTransport = &http.Transport{ + ResponseHeaderTimeout: timeOut, + } + client := http.Client{Transport: netTransport, Timeout: timeOut} + // Get the data + resp, err := client.Get(URL.String()) + if err != nil { + return fmt.Errorf("download failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("get request returned unexpected status code: %d (%s), %d was expected\n\tResponse Body: %s", resp.StatusCode, http.StatusText(resp.StatusCode), http.StatusOK, buf.Bytes()) + } + buf.ReadFrom(resp.Body) + return nil + } + case models.FileScheme: + { + if fileExists(URL.Path) { + f, err := os.Open(URL.Path) + if err != nil { + return fmt.Errorf("opening err : %w", err) + } + buf.ReadFrom(f) + f.Close() + } else { + return fmt.Errorf("artifact is not found") + } + return nil + } + default: + return fmt.Errorf("unknown url scheme") + } +} +func ExtractArtifact(artifactName string, buf *bytes.Buffer, tempDir string) error { + switch artifact := artifactName; { + case strings.HasSuffix(artifact, ".zip"): + { + c := bytes.NewReader(buf.Bytes()) + zipReader, err := zip.NewReader(c, int64(c.Len())) + if err != nil { + return fmt.Errorf("failed to create zip reader: %w", err) + } + for _, file := range zipReader.File { + + zippedFile, err := file.Open() + if err != nil { + return fmt.Errorf("unzip failed: %w", err) + } + defer zippedFile.Close() + + extractedFilePath, err := ValidatePath(file.Name, tempDir) + if err != nil { + return err + } + + if file.FileInfo().IsDir() { + os.MkdirAll(extractedFilePath, file.Mode()) + } else { + outputFile, err := os.OpenFile( + extractedFilePath, + os.O_WRONLY|os.O_CREATE|os.O_TRUNC, + file.Mode(), + ) + if err != nil { + return fmt.Errorf("unzip failed to create file: %w", err) + } + defer outputFile.Close() + + buf := copyBufPool.Get().(*bytes.Buffer) + _, err = io.CopyBuffer(outputFile, zippedFile, buf.Bytes()) + if err != nil { + return fmt.Errorf("GetArtifacts failed to copy files: %w", err) + } + copyBufPool.Put(buf) + } + } + return nil + } + case strings.HasSuffix(artifact, ".tar.gz"): + { + archive, err := gzip.NewReader(buf) + if err != nil { + return fmt.Errorf("failed to create Gzip reader: %w", err) + } + defer archive.Close() + tarReader := tar.NewReader(archive) + + for { + header, err := tarReader.Next() + + if err == io.EOF { + break + } else if err != nil { + return fmt.Errorf("untar failed: %w", err) + } + + fPath, err := ValidatePath(header.Name, tempDir) + if err != nil { + return err + } + + info := header.FileInfo() + if info.IsDir() { + if err = os.MkdirAll(fPath, info.Mode()); err != nil { + return fmt.Errorf("untar failed to create directories: %w", err) + } + continue + } + + file, err := os.OpenFile(fPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) + if err != nil { + return fmt.Errorf("untar failed to create file: %w", err) + } + defer file.Close() + + buf := copyBufPool.Get().(*bytes.Buffer) + _, err = io.CopyBuffer(file, tarReader, buf.Bytes()) + if err != nil { + return fmt.Errorf("GetArtifacts failed to copy files: %w", err) + } + copyBufPool.Put(buf) + } + return nil + } + default: + return fmt.Errorf("unknown artifact format") + } +} + +func ValidatePath(filePath string, destination string) (string, error) { + destpath := filepath.Join(destination, filePath) + if strings.Contains(filePath, "..") { + return "", fmt.Errorf(" file contains filepath (%s) that includes (..)", filePath) + } + if !strings.HasPrefix(destpath, filepath.Clean(destination)+string(os.PathSeparator)) { + return "", fmt.Errorf("%s: illegal file path", filePath) + } + return destpath, nil +} diff --git a/bpfprogs/bpf_test.go b/bpfprogs/bpf_test.go index 6c7455b9..ab237644 100644 --- a/bpfprogs/bpf_test.go +++ b/bpfprogs/bpf_test.go @@ -19,7 +19,6 @@ import ( "testing" "github.com/golang/mock/gomock" - "github.com/l3af-project/l3afd/v2/artifact" "github.com/l3af-project/l3afd/v2/config" "github.com/l3af-project/l3afd/v2/mocks" "github.com/l3af-project/l3afd/v2/models" @@ -646,7 +645,7 @@ func Test_fileExists(t *testing.T) { }, } for _, tt := range tests { - if artifact.FileExists(tt.fileName) != tt.exist { + if fileExists(tt.fileName) != tt.exist { t.Errorf("Invalid filename") } } diff --git a/bpfprogs/bpfdebug.go b/bpfprogs/bpfdebug.go index 1384ccfb..86f2e2ac 100644 --- a/bpfprogs/bpfdebug.go +++ b/bpfprogs/bpfdebug.go @@ -6,7 +6,6 @@ package bpfprogs import ( "encoding/json" "errors" - "fmt" "net" "net/http" "strings" @@ -23,12 +22,12 @@ func SetupBPFDebug(ebpfChainDebugAddr string, BPFConfigs *NFConfigs) { if _, ok := models.AllNetListeners.Load("debug_http"); !ok { tcpAddr, err := net.ResolveTCPAddr("tcp", ebpfChainDebugAddr) if err != nil { - fmt.Println("Error resolving TCP address:", err) + log.Fatal().Err(err).Msgf("unable to resolve tcpaddr %v ", ebpfChainDebugAddr) return } listener, err := net.ListenTCP("tcp", tcpAddr) if err != nil { - log.Fatal().Err(err).Msgf("unable to create net Listen") + log.Fatal().Err(err).Msgf("unable to create tcp listener") } models.AllNetListeners.Store("debug_http", listener) } diff --git a/bpfprogs/nfconfig.go b/bpfprogs/nfconfig.go index 199e79db..4c0be1b3 100644 --- a/bpfprogs/nfconfig.go +++ b/bpfprogs/nfconfig.go @@ -1485,7 +1485,8 @@ func (c *NFConfigs) DownloadAndStartProbes(element *list.Element) error { return nil } -func SerilazeProgram(e *list.Element) *models.L3AFMetaData { +// SerialzeProgram this function wil serialize the program +func SerialzeProgram(e *list.Element) *models.L3AFMetaData { tmp := &models.L3AFMetaData{} bpf := e.Value.(*BPF) tmp.BpfMaps = make([]string, 0) @@ -1543,6 +1544,7 @@ func SerilazeProgram(e *list.Element) *models.L3AFMetaData { return tmp } +// GetL3AFHOSTDATA this function will give serialize form of current l3afd state func (c *NFConfigs) GetL3AFHOSTDATA() models.L3AFALLHOSTDATA { result := models.L3AFALLHOSTDATA{} result.HostName = c.HostName @@ -1556,7 +1558,7 @@ func (c *NFConfigs) GetL3AFHOSTDATA() models.L3AFALLHOSTDATA { for k, v := range c.IngressXDPBpfs { ls := make([]*models.L3AFMetaData, 0) for e := v.Front(); e != nil; e = e.Next() { - ls = append(ls, SerilazeProgram(e)) + ls = append(ls, SerialzeProgram(e)) } result.IngressXDPBpfs[k] = ls } @@ -1565,7 +1567,7 @@ func (c *NFConfigs) GetL3AFHOSTDATA() models.L3AFALLHOSTDATA { for k, v := range c.IngressTCBpfs { ls := make([]*models.L3AFMetaData, 0) for e := v.Front(); e != nil; e = e.Next() { - ls = append(ls, SerilazeProgram(e)) + ls = append(ls, SerialzeProgram(e)) } result.IngressTCBpfs[k] = ls } @@ -1574,13 +1576,13 @@ func (c *NFConfigs) GetL3AFHOSTDATA() models.L3AFALLHOSTDATA { for k, v := range c.EgressTCBpfs { ls := make([]*models.L3AFMetaData, 0) for e := v.Front(); e != nil; e = e.Next() { - ls = append(ls, SerilazeProgram(e)) + ls = append(ls, SerialzeProgram(e)) } result.EgressTCBpfs[k] = ls } } for e := c.ProbesBpfs.Front(); e != nil; e = e.Next() { - result.ProbesBpfs = append(result.ProbesBpfs, *SerilazeProgram(e)) + result.ProbesBpfs = append(result.ProbesBpfs, *SerialzeProgram(e)) } metrics, _ := prometheus.DefaultGatherer.Gather() result.AllStats = make([]models.MetricVec, 0) @@ -1612,6 +1614,7 @@ func (c *NFConfigs) GetL3AFHOSTDATA() models.L3AFALLHOSTDATA { return result } +// StartAllUserProgramsAndProbes this function will restart all the User Programs and probes func (c *NFConfigs) StartAllUserProgramsAndProbes() error { if c.IngressXDPBpfs != nil { for iface, v := range c.IngressXDPBpfs { @@ -1749,6 +1752,7 @@ func (c *NFConfigs) StartAllUserProgramsAndProbes() error { return nil } +// StopAllProbes this function will stop all the probes func (c *NFConfigs) StopAllProbes() { if c.IngressXDPBpfs != nil { for _, v := range c.IngressXDPBpfs { diff --git a/config/config.go b/config/config.go index ec69e2a3..b1328f35 100644 --- a/config/config.go +++ b/config/config.go @@ -32,8 +32,6 @@ type Config struct { BpfMapDefaultPath string // Flag to enable chaining with root program BpfChainingEnabled bool - TimetoRestart int - BasePath string FileLogLocation string FileLogMaxSize int @@ -90,6 +88,12 @@ type Config struct { MTLSServerKeyFilename string MTLSCertExpiryWarningDays int MTLSSANMatchRules []string + + // graceful-restart + TimetoRestart int + BasePath string + RestartArtifactURL string + VersionLimit int } // ReadConfig - Initializes configuration from file @@ -110,14 +114,12 @@ func ReadConfig(configPath string) (*Config, error) { DataCenter: LoadConfigString(confReader, "l3afd", "datacenter"), BPFDir: LoadConfigString(confReader, "l3afd", "bpf-dir"), BPFLogDir: LoadOptionalConfigString(confReader, "l3afd", "bpf-log-dir", ""), - BasePath: LoadOptionalConfigString(confReader, "l3afd", "basepath", "/usr/local/l3afd"), MinKernelMajorVer: LoadOptionalConfigInt(confReader, "l3afd", "kernel-major-version", 5), MinKernelMinorVer: LoadOptionalConfigInt(confReader, "l3afd", "kernel-minor-version", 15), FileLogLocation: LoadOptionalConfigString(confReader, "l3afd", "file-log-location", ""), FileLogMaxSize: LoadOptionalConfigInt(confReader, "l3afd", "file-log-max-size", 100), FileLogMaxBackups: LoadOptionalConfigInt(confReader, "l3afd", "file-log-max-backups", 20), FileLogMaxAge: LoadOptionalConfigInt(confReader, "l3afd", "file-log-max-age", 60), - TimetoRestart: LoadOptionalConfigInt(confReader, "l3afd", "time-to-restart", 7), EBPFRepoURL: LoadConfigString(confReader, "ebpf-repo", "url"), HttpClientTimeout: LoadOptionalConfigDuration(confReader, "l3afd", "http-client-timeout", 30*time.Second), MaxEBPFReStartCount: LoadOptionalConfigInt(confReader, "l3afd", "max-ebpf-restart-count", 3), @@ -158,6 +160,10 @@ func ReadConfig(configPath string) (*Config, error) { MTLSServerKeyFilename: LoadOptionalConfigString(confReader, "mtls", "server-key-filename", "server.key"), MTLSCertExpiryWarningDays: LoadOptionalConfigInt(confReader, "mtls", "cert-expiry-warning-days", 30), MTLSSANMatchRules: strings.Split(LoadOptionalConfigString(confReader, "mtls", "san-match-rules", ""), ","), + BasePath: LoadOptionalConfigString(confReader, "graceful-restart", "basepath", "/usr/local/l3afd"), + TimetoRestart: LoadOptionalConfigInt(confReader, "graceful-restart", "time-to-restart", 7), + VersionLimit: LoadOptionalConfigInt(confReader, "graceful-restart", "version-limit", 100), + RestartArtifactURL: LoadOptionalConfigString(confReader, "graceful-restart", "restart-artifacts-url", "file:///srv/l3afd"), }, nil } diff --git a/config/l3afd.cfg b/config/l3afd.cfg index 85a40b7d..abdb47eb 100644 --- a/config/l3afd.cfg +++ b/config/l3afd.cfg @@ -14,12 +14,11 @@ bpf-chaining-enabled: true swagger-api-enabled: true environment: DEV BpfMapDefaultPath: /sys/fs/bpf -time-to-restart: 7 -basepath: /usr/local/l3afd [ebpf-repo] url: file:///srv/l3afd + [web] metrics-addr: 0.0.0.0:8898 ebpf-poll-interval: 30s @@ -72,3 +71,9 @@ enabled: false [l3af-config-store] filename: /var/l3afd/l3af-config.json + +[graceful-restart] +restart-artifacts-url: file:///srv/l3afd +time-to-restart: 7 +basepath: /usr/local/l3afd +version-limit: 100 diff --git a/main.go b/main.go index cf63e56c..51d51d4f 100644 --- a/main.go +++ b/main.go @@ -101,9 +101,9 @@ func main() { log.Info().Msgf("Saving logs to file: %s", conf.FileLogLocation) saveLogsToFile(conf) } - + populateVersions(conf) if err = pidfile.CheckPIDConflict(conf.PIDFilename); err != nil { - if err = setupForRestart(ctx, conf); err != nil { + if err = setupForRestartOuter(ctx, conf); err != nil { log.Warn().Msg("Doing Normal Startup") } else { log.Fatal().Err(err).Msgf("The PID file: %s, is in an unacceptable state", conf.PIDFilename) @@ -247,42 +247,60 @@ func ReadConfigsFromConfigStore(conf *config.Config) ([]models.L3afBPFPrograms, return t, nil } -func HandleErr(e error, msg string) { - if e == nil { - return - } - log.Fatal().Err(e).Msgf(msg) - sendState("Failed") - os.Exit(0) -} -func setupForRestart(ctx context.Context, conf *config.Config) error { +func setupForRestartOuter(ctx context.Context, conf *config.Config) error { if _, err := os.Stat(models.HostSock); os.IsNotExist(err) { return err } stateSockPath = models.StateSock models.IsReadOnly = true + err := setupForRestart(ctx, conf) + if err != nil { + sendState("Failed") + log.Fatal().Err(err).Msg("unable to restart the l3afd") + } + // we need to write code to send ready status + sendState("Ready") + models.IsReadOnly = false + <-models.CloseForRestart + os.Exit(0) + return nil +} + +func setupForRestart(ctx context.Context, conf *config.Config) error { // Now you need to write client side code conn, err := net.Dial("unix", models.HostSock) - HandleErr(err, "unable to dial unix domain socket") + if err != nil { + return fmt.Errorf("unable to dial unix domain socket : %w", err) + } defer conn.Close() decoder := gob.NewDecoder(conn) var t models.L3AFALLHOSTDATA err = decoder.Decode(&t) - HandleErr(err, "unable to decode") + if err != nil { + return fmt.Errorf("unable to decode") + } machineHostname, err := os.Hostname() - HandleErr(err, "unable to fetch the hostname") + if err != nil { + return fmt.Errorf("unable to fetch the hostname") + } l, err := restart.Getnetlistener(3, "stat_server") - HandleErr(err, "getting stat_server listener failed") + if err != nil { + return fmt.Errorf("getting stat_server listener failed") + } models.AllNetListeners.Store("stat_http", l) l, err = restart.Getnetlistener(4, "main_server") - HandleErr(err, "getting main_server listener failed") + if err != nil { + return fmt.Errorf("getting main_server listener failed") + } models.AllNetListeners.Store("main_http", l) if conf.EBPFChainDebugEnabled { l, err = restart.Getnetlistener(5, "debug_server") - HandleErr(err, "getting main_server listener failed") + if err != nil { + return fmt.Errorf("getting main_server listener failed") + } models.AllNetListeners.Store("debug_http", l) } // setup Metrics endpoint @@ -294,25 +312,30 @@ func setupForRestart(ctx context.Context, conf *config.Config) error { ebpfConfigs, err := restart.Convert(ctx, t, conf) ebpfConfigs.BpfMetricsMon = bpfM ebpfConfigs.ProcessMon = pMon - HandleErr(err, "Failed to convert deserilaze the state") + if err != nil { + return fmt.Errorf("failed to convert deserilaze the state") + } err = ebpfConfigs.StartAllUserProgramsAndProbes() - HandleErr(err, "failed to start all the user programs and probes") + if err != nil { + return fmt.Errorf("failed to start all the user programs and probes") + } err = apis.StartConfigWatcher(ctx, machineHostname, daemonName, conf, ebpfConfigs) - HandleErr(err, "Starting config Watcher failed") + if err != nil { + return fmt.Errorf("starting config Watcher failed") + } err = handlers.InitConfigs(ebpfConfigs) - HandleErr(err, "L3afd failed to initialise configs") + if err != nil { + return fmt.Errorf("l3afd failed to initialise configs") + } if conf.EBPFChainDebugEnabled { bpfprogs.SetupBPFDebug(conf.EBPFChainDebugAddr, ebpfConfigs) } ebpfConfigs.ProcessMon.PCheckStart(ebpfConfigs.IngressXDPBpfs, ebpfConfigs.IngressTCBpfs, ebpfConfigs.EgressTCBpfs, &ebpfConfigs.ProbesBpfs) ebpfConfigs.BpfMetricsMon.BpfMetricsStart(ebpfConfigs.IngressXDPBpfs, ebpfConfigs.IngressTCBpfs, ebpfConfigs.EgressTCBpfs, &ebpfConfigs.ProbesBpfs) err = pidfile.CreatePID(conf.PIDFilename) - HandleErr(err, fmt.Sprintf("The PID file: %s, could not be created", conf.PIDFilename)) - // we need to write code to send ready status - sendState("Ready") - models.IsReadOnly = false - <-models.CloseForRestart - os.Exit(0) + if err != nil { + return fmt.Errorf("the PID file: %s, could not be created", conf.PIDFilename) + } return nil } @@ -342,3 +365,16 @@ func sendState(s string) { conn.Close() ln.Close() } + +// populateVersions is to suppress codeql warning - Uncontrolled data used in network request +func populateVersions(conf *config.Config) { + models.AvailableVersions = make(map[string]string) + for i := 0; i <= conf.VersionLimit; i++ { + for j := 0; j <= conf.VersionLimit; j++ { + for k := 0; k <= conf.VersionLimit; k++ { + version := fmt.Sprintf("v%d.%d.%d", i, j, k) + models.AvailableVersions[version] = version + } + } + } +} diff --git a/models/l3afd.go b/models/l3afd.go index eece2acb..b6a84bc5 100644 --- a/models/l3afd.go +++ b/models/l3afd.go @@ -162,24 +162,23 @@ type L3AFALLHOSTDATA struct { AllStats []MetricVec } -var CloseForRestart chan struct{} +type RestartConfig struct { + HostName string `json:"hostname"` + Version string `json:"version"` +} +var CloseForRestart chan struct{} var AllNetListeners sync.Map - var CurrentWriteReq int var StateLock sync.Mutex var IsReadOnly bool +var AvailableVersions map[string]string const HttpScheme string = "http" const HttpsScheme string = "https" const FileScheme string = "file" -// Please Do not changes because they are means of communication between graceful restarts +// Please Do not make changes in socketpaths because they are means of communication between graceful restarts const HostSock string = "/tmp/l3afd.sock" const StateSock string = "/tmp/l3afstate.sock" - -type RestartConfig struct { - HostName string `json:"hostname"` - Version string `json:"version"` - ArtifactURL string `json:"artifacturl"` -} +const L3AFDRestartArtifactName string = "l3afd.tar.gz" diff --git a/restart/restart.go b/restart/restart.go index 4da84865..6140085f 100644 --- a/restart/restart.go +++ b/restart/restart.go @@ -8,13 +8,13 @@ import ( "fmt" "net" "os" + "path" "path/filepath" "strings" "sync" "github.com/cilium/ebpf" "github.com/cilium/ebpf/link" - "github.com/l3af-project/l3afd/v2/artifact" "github.com/l3af-project/l3afd/v2/bpfprogs" "github.com/l3af-project/l3afd/v2/config" "github.com/l3af-project/l3afd/v2/models" @@ -117,7 +117,7 @@ func getMetricsMaps(input map[string]models.MetaMetricsBPFMap, b *bpfprogs.BPF, return nil } -func DeserilazeProgram(ctx context.Context, r *models.L3AFMetaData, hostconfig *config.Config, iface string) (*bpfprogs.BPF, error) { +func DeserializeProgram(ctx context.Context, r *models.L3AFMetaData, hostconfig *config.Config, iface string) (*bpfprogs.BPF, error) { g := &bpfprogs.BPF{} g.Program = r.Program g.FilePath = r.FilePath @@ -207,9 +207,9 @@ func Convert(ctx context.Context, t models.L3AFALLHOSTDATA, hostconfig *config.C for k, v := range t.IngressXDPBpfs { l := list.New() for _, r := range v { - f, err := DeserilazeProgram(ctx, r, hostconfig, k) + f, err := DeserializeProgram(ctx, r, hostconfig, k) if err != nil { - log.Err(err).Msg("Deserialization failed for xdpingress") + log.Err(err).Msg("Deserialization failed for xdp ingress programs") return nil, err } l.PushBack(f) @@ -221,9 +221,9 @@ func Convert(ctx context.Context, t models.L3AFALLHOSTDATA, hostconfig *config.C for k, v := range t.IngressTCBpfs { l := list.New() for _, r := range v { - f, err := DeserilazeProgram(ctx, r, hostconfig, k) + f, err := DeserializeProgram(ctx, r, hostconfig, k) if err != nil { - log.Err(err).Msg("Deserialization failed for tcingress") + log.Err(err).Msg("Deserialization failed for tc ingress programs") return nil, err } l.PushBack(f) @@ -235,9 +235,9 @@ func Convert(ctx context.Context, t models.L3AFALLHOSTDATA, hostconfig *config.C for k, v := range t.EgressTCBpfs { l := list.New() for _, r := range v { - f, err := DeserilazeProgram(ctx, r, hostconfig, k) + f, err := DeserializeProgram(ctx, r, hostconfig, k) if err != nil { - log.Err(err).Msg("Deserialization failed for tcegress") + log.Err(err).Msg("Deserialization failed for tc egress programs") return nil, err } l.PushBack(f) @@ -277,7 +277,7 @@ func Getnetlistener(fd int, fname string) (*net.TCPListener, error) { } lf, e := l.(*net.TCPListener) if !e { - return nil, fmt.Errorf("unable to covert to tcp listner") + return nil, fmt.Errorf("unable to convert to tcp listener") } file.Close() return lf, nil @@ -301,14 +301,11 @@ func ReadSymlink(symlink string) (string, error) { return originalPath, nil } -func GetNewVersion(urlpath string, oldVersion, newVersion string, conf *config.Config) error { +func GetNewVersion(artifactName, oldVersion, newVersion string, conf *config.Config) error { if oldVersion == newVersion { return nil } - newVersionPath := conf.BasePath + "/" + newVersion - if !strings.HasPrefix(conf.BasePath, filepath.Clean(newVersionPath)+string(os.PathSeparator)) { - return fmt.Errorf("malicious input given to the restart api") - } + newVersionPath := filepath.Clean(filepath.Join(conf.BasePath, newVersion)) err := os.RemoveAll(newVersionPath) if err != nil { return fmt.Errorf("error while deleting directory: %w", err) @@ -319,39 +316,35 @@ func GetNewVersion(urlpath string, oldVersion, newVersion string, conf *config.C } // now I need to download artifacts buf := &bytes.Buffer{} - err = artifact.DownloadArtifact(urlpath, conf.HttpClientTimeout, buf) + urlpath := path.Join(conf.RestartArtifactURL, newVersion, artifactName) + err = bpfprogs.DownloadArtifact(urlpath, conf.HttpClientTimeout, buf) if err != nil { return fmt.Errorf("unable to download artifacts %w", err) } - sp := strings.Split(urlpath, "/") - artifactName := sp[len(sp)-1] - err = artifact.ExtractArtifact(artifactName, buf, newVersionPath) - dir := strings.Split(artifactName, ".")[0] + err = bpfprogs.ExtractArtifact(artifactName, buf, newVersionPath) if err != nil { return fmt.Errorf("unable to extract artifacts %w", err) } + // you need to store the old path for rollback purposes - // we will remove symlink - err = RemoveSymlink(conf.BasePath + "/latest/l3afd") + err = RemoveSymlink(filepath.Join(conf.BasePath, "latest/l3afd")) if err != nil { return fmt.Errorf("unable to remove symlink %w", err) } - err = RemoveSymlink(conf.BasePath + "/latest/l3afd.cfg") + err = RemoveSymlink(filepath.Join(conf.BasePath, "latest/l3afd.cfg")) if err != nil { return fmt.Errorf("unable to remove symlink %w", err) } // add new symlink - - err = AddSymlink(newVersionPath+"/"+dir+"/l3afd", conf.BasePath+"/latest/l3afd") + err = AddSymlink(filepath.Join(newVersionPath, "l3afd", "l3afd"), filepath.Join(conf.BasePath, "latest/l3afd")) if err != nil { return fmt.Errorf("unable to add symlink %w", err) } - err = AddSymlink(newVersionPath+"/"+dir+"/l3afd.cfg", conf.BasePath+"/latest/l3afd.cfg") + err = AddSymlink(filepath.Join(newVersionPath, "l3afd", "l3afd.cfg"), filepath.Join(conf.BasePath, "latest/l3afd.cfg")) if err != nil { return fmt.Errorf("unable to add symlink %w", err) } - // now we are good return nil } @@ -359,29 +352,27 @@ func RollBackSymlink(oldCfgPath, oldBinPath string, oldVersion, newVersion strin if oldVersion == newVersion { return nil } - // you need to store the old path for rollback purposes - // we will remove symlink - err := RemoveSymlink(conf.BasePath + "/latest/l3afd") + + err := RemoveSymlink(filepath.Join(conf.BasePath, "latest/l3afd")) if err != nil { return fmt.Errorf("unable to remove symlink %w", err) } - err = RemoveSymlink(conf.BasePath + "/latest/l3afd.cfg") + err = RemoveSymlink(filepath.Join(conf.BasePath, "latest/l3afd.cfg")) if err != nil { return fmt.Errorf("unable to remove symlink %w", err) } // add new symlink - - err = AddSymlink(oldBinPath, conf.BasePath+"/latest/l3afd") + err = AddSymlink(oldBinPath, filepath.Join(conf.BasePath, "latest/l3afd")) if err != nil { return fmt.Errorf("unable to add symlink %w", err) } - err = AddSymlink(oldCfgPath, conf.BasePath+"/latest/l3afd.cfg") + err = AddSymlink(oldCfgPath, filepath.Join(conf.BasePath, "latest/l3afd.cfg")) if err != nil { return fmt.Errorf("unable to add symlink %w", err) } - newVersionPath := conf.BasePath + "/" + newVersion + newVersionPath := filepath.Join(conf.BasePath, newVersion) if strings.Contains(newVersionPath, "..") { return fmt.Errorf("malicious path") } diff --git a/stats/metrics.go b/stats/metrics.go index d49ecec4..0a5d05b2 100644 --- a/stats/metrics.go +++ b/stats/metrics.go @@ -5,7 +5,6 @@ package stats import ( "errors" - "fmt" "net" "net/http" @@ -67,7 +66,7 @@ func SetupMetrics(hostname, daemonName, metricsAddr string) { Name: "BPFUpdateFailedCount", Help: "The count of Failed eBPF programs updates", }, - []string{"host", "ebpf_program", "direction", "interface_name"}, + []string{"host", "bpf_program", "direction", "interface_name"}, ) BPFUpdateFailedCount = bpfUpdateFailedCountVec.MustCurryWith(prometheus.Labels{"host": hostname}) @@ -125,7 +124,7 @@ func SetupMetrics(hostname, daemonName, metricsAddr string) { if _, ok := models.AllNetListeners.Load("stat_http"); !ok { tcpAddr, err := net.ResolveTCPAddr("tcp", metricsAddr) if err != nil { - fmt.Println("Error resolving TCP address:", err) + log.Fatal().Err(err).Msg("Error resolving TCP address") return } listener, err := net.ListenTCP("tcp", tcpAddr)