Skip to content

Commit

Permalink
adding simlink stuff
Browse files Browse the repository at this point in the history
Signed-off-by: Atul-source <atulprajapati6031@gmail.com>
  • Loading branch information
Atul-source committed Aug 28, 2024
1 parent 1805075 commit e292fbf
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 52 deletions.
122 changes: 106 additions & 16 deletions apis/handlers/restart_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ package handlers

import (
"encoding/gob"
"encoding/json"
"fmt"
"io"
"net"
"os"
"os/exec"
"strconv"
"strings"
"syscall"
"time"

Expand All @@ -20,6 +23,7 @@ import (
"github.com/l3af-project/l3afd/v2/bpfprogs"
"github.com/l3af-project/l3afd/v2/models"
"github.com/l3af-project/l3afd/v2/pidfile"
"github.com/l3af-project/l3afd/v2/restart"
)

// HandleRestart Store meta data about ebpf programs and exit
Expand Down Expand Up @@ -48,6 +52,25 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc {
statusCode = http.StatusInternalServerError
return
}
if r.Body == nil {
log.Warn().Msgf("Empty request body")
return
}
bodyBuffer, err := io.ReadAll(r.Body)
if err != nil {
mesg = fmt.Sprintf("failed to read request body: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}

var t models.RestartConfig
if err := json.Unmarshal(bodyBuffer, &t); err != nil {
mesg = fmt.Sprintf("failed to unmarshal payload: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}
defer func() {
models.IsReadOnly = false
}()
Expand All @@ -62,12 +85,39 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc {
models.StateLock.Unlock()
time.Sleep(time.Millisecond)
}

err, oldCfgPath := restart.ReadSymlink(bpfcfg.HostConfig.BasePath + "/latest/l3afd.cfg")
if err != nil {
mesg = fmt.Sprintf("failed read simlink: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}
err, oldBinPath := restart.ReadSymlink(bpfcfg.HostConfig.BasePath + "/latest/l3afd")
if err != nil {
mesg = fmt.Sprintf("failed to read simlink: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}
oldVersion := strings.Split(strings.Trim(oldBinPath, bpfcfg.HostConfig.BasePath+"/"), "/")[0]

err = restart.GetNewVersion(t.ArtifactURL, oldVersion, t.Version, bpfcfg.HostConfig)
if err != nil {
mesg = fmt.Sprintf("failed to getNewVersion: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig)
mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err)
return
}
// Now our system is in Readonly state
bpfProgs := bpfcfg.GetL3AFHOSTDATA()
bpfProgs.InRestart = true
ln, err := net.Listen("unix", bpfcfg.HostConfig.HostSock)
ln, err := net.Listen("unix", models.HostSock)
if err != nil {
log.Err(err)
err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig)
mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err)
statusCode = http.StatusInternalServerError
return
}
Expand All @@ -88,6 +138,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc {
srverror <- err
return
}
srverror <- nil
}()
files := make([]*os.File, 3)
srvToIndex := make(map[string]int)
Expand All @@ -99,44 +150,49 @@ 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)
mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err)
statusCode = http.StatusInternalServerError
return
}
newFile := os.NewFile(uintptr(lf.Fd()), "dupFdlistner"+strconv.Itoa(idx))
files[idx] = newFile
}
// we have added
cmd := exec.Command(bpfcfg.HostConfig.BaseBinPath+"/l3afd", "--config", bpfcfg.HostConfig.BaseCfgPath+"/l3afd.cfg")
cmd := exec.Command(bpfcfg.HostConfig.BasePath+"/latest/l3afd", "--config", bpfcfg.HostConfig.BasePath+"/latest/l3afd.cfg")
cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.ExtraFiles = files
// checking srv error
if len(srverror) == 1 {
statusCode = http.StatusInternalServerError
log.Err(<-srverror)
return
}
bpfcfg.StopAllProbes()
log.Info().Msg("Starting child Process")
err = cmd.Start()
if err != nil {
log.Error().Msgf("%v", err)
statusCode = http.StatusInternalServerError
mesg = mesg + fmt.Sprintf("not able to start new instance %v", err)
// write a function a to do cleanup of other process if necessary
err = cmd.Process.Kill()
if err != nil {
fmt.Println(err)
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to kill the new instance %v", err)
}
err = bpfcfg.StartAllUserProgramsAndProbes()
if err != nil {
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to start all userprograms and probes: %v", err)
}
err = pidfile.CreatePID(bpfcfg.HostConfig.PIDFilename)
if err != nil {
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to create pid file: %v", err)
}
err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig)
if err != nil {
mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err)
}
statusCode = http.StatusInternalServerError
return
}
NewProcessStatus := make(chan string)
Expand All @@ -146,7 +202,7 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc {
var conn net.Conn
f := false
for i := 1; i <= bpfcfg.HostConfig.TimetoRestart; i++ {
conn, err = net.Dial("unix", bpfcfg.HostConfig.StateSock)
conn, err = net.Dial("unix", models.StateSock)
if err == nil {
f = true
break
Expand All @@ -168,33 +224,67 @@ func HandleRestart(bpfcfg *bpfprogs.NFConfigs) http.HandlerFunc {
}
NewProcessStatus <- data
}()

// time to bootup
for i := 0; i < bpfcfg.HostConfig.TimetoRestart; i++ {
if len(srverror) == 1 {
select {
case terr := <-srverror:
if terr != nil {
statusCode = http.StatusInternalServerError
// write a function a to do cleanup of other process if necessary
err = cmd.Process.Kill()
if err != nil {
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to kill the new instance %v", err)
}
err = bpfcfg.StartAllUserProgramsAndProbes()
if err != nil {
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to start all userprograms and probes: %v", err)
}
err = pidfile.CreatePID(bpfcfg.HostConfig.PIDFilename)
if err != nil {
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to create pid file: %v", err)
}
err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig)
if err != nil {
mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err)
}
statusCode = http.StatusInternalServerError
log.Err(<-srverror)
return
}
time.Sleep(1 * time.Second)
break
default:
time.Sleep(time.Second)
}

st := <-NewProcessStatus
if st == "Failed" {
// write a function a to do cleanup of other process if necessary
err = cmd.Process.Kill()
if err != nil {
fmt.Println(err)
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to kill the new instance %v", err)
}
err = bpfcfg.StartAllUserProgramsAndProbes()
if err != nil {
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to start all userprograms and probes: %v", err)
}
err = pidfile.CreatePID(bpfcfg.HostConfig.PIDFilename)
if err != nil {
log.Error().Msgf("%v", err)
mesg = mesg + fmt.Sprintf("not able to create pid file: %v", err)
}
err = restart.RollBackSymlink(oldCfgPath, oldBinPath, oldVersion, t.Version, bpfcfg.HostConfig)
if err != nil {
mesg = mesg + fmt.Sprintf("rollback of symlink failed: %v", err)
}
statusCode = http.StatusInternalServerError
return
} else {
log.Info().Msgf("doing exiting old process")
models.CloseForRestart <- struct{}{}
}
}
Expand Down
39 changes: 23 additions & 16 deletions bpfprogs/bpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ var (
//lint:ignore U1000 avoid false linter error on windows, since this variable is only used in linux code
const executePerm uint32 = 0111
const bpfStatus string = "RUNNING"
const httpScheme string = "http"
const httpsScheme string = "https"
const fileScheme string = "file"

// BPF defines run time details for BPFProgram.
type BPF struct {
Expand Down Expand Up @@ -629,10 +626,22 @@ func (b *BPF) GetArtifacts(conf *config.Config) error {

URL.Path = path.Join(URL.Path, b.Program.Name, b.Program.Version, platform, b.Program.Artifact)
log.Info().Msgf("Retrieving artifact - %s", URL)
err = DownloadArtifact(URL, conf.HttpClientTimeout, buf)
tempDir := filepath.Join(conf.BPFDir, b.Program.Name, b.Program.Version)
err = ExtractArtifact(b.Program.Artifact, buf, tempDir)
if err != nil {
return fmt.Errorf("not able to extract artifact %w", err)
}
newDir := strings.Split(b.Program.Artifact, ".")
b.FilePath = filepath.Join(tempDir, newDir[0])
return nil
}

func DownloadArtifact(URL *url.URL, timeout time.Duration, buf *bytes.Buffer) error {
switch URL.Scheme {
case httpsScheme, httpScheme:
case models.HttpScheme, models.HttpsScheme:
{
timeOut := time.Duration(conf.HttpClientTimeout) * time.Second
timeOut := time.Duration(timeout) * time.Second
var netTransport = &http.Transport{
ResponseHeaderTimeout: timeOut,
}
Expand All @@ -649,8 +658,9 @@ func (b *BPF) GetArtifacts(conf *config.Config) error {
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 fileScheme:
case models.FileScheme:
{
if fileExists(URL.Path) {
f, err := os.Open(URL.Path)
Expand All @@ -662,19 +672,21 @@ func (b *BPF) GetArtifacts(conf *config.Config) error {
} else {
return fmt.Errorf("artifact is not found")
}
return nil
}
default:
return fmt.Errorf("unknown url scheme")
}

switch artifact := b.Program.Artifact; {
}
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)
}
tempDir := filepath.Join(conf.BPFDir, b.Program.Name, b.Program.Version)

for _, file := range zipReader.File {

zippedFile, err := file.Open()
Expand Down Expand Up @@ -709,19 +721,16 @@ func (b *BPF) GetArtifacts(conf *config.Config) error {
copyBufPool.Put(buf)
}
}
newDir := strings.Split(b.Program.Artifact, ".")
b.FilePath = filepath.Join(tempDir, newDir[0])
return nil
}
case strings.HasSuffix(b.Program.Artifact, ".tar.gz"):
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)
tempDir := filepath.Join(conf.BPFDir, b.Program.Name, b.Program.Version)

for {
header, err := tarReader.Next()
Expand Down Expand Up @@ -758,8 +767,6 @@ func (b *BPF) GetArtifacts(conf *config.Config) error {
}
copyBufPool.Put(buf)
}
newDir := strings.Split(b.Program.Artifact, ".")
b.FilePath = filepath.Join(tempDir, newDir[0])
return nil
}
default:
Expand Down
12 changes: 2 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Config struct {
// Flag to enable chaining with root program
BpfChainingEnabled bool
TimetoRestart int
BasePath string

FileLogLocation string
FileLogMaxSize int
Expand Down Expand Up @@ -89,12 +90,6 @@ type Config struct {
MTLSServerKeyFilename string
MTLSCertExpiryWarningDays int
MTLSSANMatchRules []string

// RestartConfig
HostSock string
StateSock string
BaseBinPath string
BaseCfgPath string
}

// ReadConfig - Initializes configuration from file
Expand All @@ -115,6 +110,7 @@ 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", ""),
Expand Down Expand Up @@ -162,10 +158,6 @@ 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", ""), ","),
HostSock: LoadOptionalConfigString(confReader, "restart-config", "hostsock", "/tmp/l3afd.sock"),
StateSock: LoadOptionalConfigString(confReader, "restart-config", "statesock", "/tmp/l3afstate.sock"),
BaseBinPath: LoadOptionalConfigString(confReader, "restart-config", "basebinpath", "/usr/local/l3afd"),
BaseCfgPath: LoadOptionalConfigString(confReader, "restart-config", "basecfgpath", "/usr/local/l3afd"),
}, nil
}

Expand Down
7 changes: 1 addition & 6 deletions config/l3afd.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ swagger-api-enabled: true
environment: DEV
BpfMapDefaultPath: /sys/fs/bpf
time-to-restart: 7
basepath: /usr/local/l3afd

[ebpf-repo]
url: file:///srv/l3afd
Expand Down Expand Up @@ -71,9 +72,3 @@ enabled: false

[l3af-config-store]
filename: /var/l3afd/l3af-config.json

[restart-config]
hostsock: /tmp/l3afd.sock
statesock: /tmp/l3afstate.sock
basebinpath: /usr/local/l3afd
basecfgpath: /usr/local/l3afd
Loading

0 comments on commit e292fbf

Please sign in to comment.